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.

791 lines
21 KiB

  1. #define UNICODE 1
  2. #define _UNICODE 1
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include <nt.h>
  6. #include <ntrtl.h>
  7. #include <nturtl.h>
  8. #include <ntstatus.h>
  9. #include <ntioapi.h>
  10. #include <windows.h>
  11. #include <tchar.h>
  12. #include <dbt.h>
  13. #include <devguid.h>
  14. #include <eh.h>
  15. #include <shlwapi.h>
  16. #include <dfsutil.hxx>
  17. #define UNICODE_PATH_SEP L'\\'
  18. DWORD
  19. DeleteLinkReparsePoint(
  20. PUNICODE_STRING pDirectoryName,
  21. HANDLE ParentHandle );
  22. DWORD DisplayFileName(
  23. PTSTR pszVolume,
  24. HANDLE hVolume,
  25. LONGLONG llFileId,
  26. BOOL fRemoveDirectory);
  27. void
  28. CountReparsePoints(PCTSTR pcszInput);
  29. DWORD
  30. xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir);
  31. HANDLE xOpenReparseIndex(PCTSTR pcszVolume);
  32. HANDLE xOpenVolume(PCTSTR pcszVolume);
  33. BOOL xGetNextReparseRecord(
  34. HANDLE hIndex,
  35. PFILE_REPARSE_POINT_INFORMATION ReparseInfo);
  36. DWORD CountReparsePoints(LPWSTR pcszInput, BOOL fRemoveDirectory)
  37. {
  38. PTSTR pszVolume = NULL;
  39. DWORD dwCount = 0;
  40. DWORD Error = 0;
  41. BOOL fDone = TRUE;
  42. HANDLE hIndex = INVALID_HANDLE_VALUE;
  43. HANDLE hVolume = INVALID_HANDLE_VALUE;
  44. FILE_REPARSE_POINT_INFORMATION ReparseInfo;
  45. Error = xGetRootDirectory(
  46. pcszInput,
  47. &pszVolume);
  48. if(Error != 0)
  49. {
  50. return Error;
  51. }
  52. hIndex = xOpenReparseIndex(
  53. pszVolume);
  54. if(hIndex == INVALID_HANDLE_VALUE)
  55. {
  56. Error = GetLastError();
  57. goto Exit;
  58. }
  59. hVolume = xOpenVolume(
  60. pszVolume);
  61. if(hVolume == INVALID_HANDLE_VALUE)
  62. {
  63. Error = GetLastError();
  64. goto Exit;
  65. }
  66. fDone = xGetNextReparseRecord(
  67. hIndex,
  68. &ReparseInfo);
  69. while (!fDone)
  70. {
  71. if (IO_REPARSE_TAG_DFS == ReparseInfo.Tag)
  72. {
  73. dwCount++;
  74. DisplayFileName(
  75. pszVolume,
  76. hVolume,
  77. ReparseInfo.FileReference,
  78. fRemoveDirectory);
  79. }
  80. fDone = xGetNextReparseRecord(
  81. hIndex,
  82. &ReparseInfo);
  83. }
  84. Error = GetLastError();
  85. Exit:
  86. if(hIndex != INVALID_HANDLE_VALUE )
  87. {
  88. CloseHandle(hIndex);
  89. hIndex = INVALID_HANDLE_VALUE;
  90. }
  91. _tprintf(
  92. _T("This volume (%ws) contains %u DFS Directories.\n"),
  93. pszVolume,
  94. dwCount);
  95. if (hVolume!=INVALID_HANDLE_VALUE)
  96. {
  97. CloseHandle(hVolume);
  98. }
  99. if(pszVolume)
  100. {
  101. delete []pszVolume;
  102. }
  103. return Error;
  104. }
  105. DWORD
  106. xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir)
  107. {
  108. DWORD dwBufferSize = MAX_PATH;
  109. PTSTR pszTemp = NULL;
  110. BOOL bResult = FALSE;
  111. DWORD dwGleCode = 0;
  112. *pszRootDir = NULL;
  113. do
  114. {
  115. pszTemp = new TCHAR[dwBufferSize];
  116. if(pszTemp == NULL)
  117. {
  118. dwGleCode = ERROR_NOT_ENOUGH_MEMORY;
  119. return dwGleCode;
  120. }
  121. bResult = GetVolumePathName(
  122. pcszInput,
  123. pszTemp,
  124. dwBufferSize);
  125. if (!bResult)
  126. {
  127. delete []pszTemp;
  128. dwGleCode = GetLastError();
  129. if (ERROR_BUFFER_OVERFLOW==dwGleCode)
  130. {
  131. dwBufferSize *= 2;
  132. }
  133. else
  134. {
  135. break;
  136. }
  137. }
  138. } while (!bResult);
  139. *pszRootDir = pszTemp;
  140. return dwGleCode;
  141. }
  142. HANDLE xOpenReparseIndex(PCTSTR pcszVolume)
  143. {
  144. HANDLE hReparseIndex = INVALID_HANDLE_VALUE;
  145. PTSTR pszReparseIndex = NULL;
  146. DWORD Error = 0;
  147. pszReparseIndex = new TCHAR[_tcslen(pcszVolume)+64];
  148. if(pszReparseIndex == NULL)
  149. {
  150. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  151. return hReparseIndex;
  152. }
  153. _tcscpy(
  154. pszReparseIndex,
  155. pcszVolume);
  156. PathAddBackslash(pszReparseIndex);
  157. _tcscat(
  158. pszReparseIndex,
  159. _T("$Extend\\$Reparse:$R:$INDEX_ALLOCATION"));
  160. hReparseIndex = CreateFile(
  161. pszReparseIndex,
  162. GENERIC_READ,
  163. FILE_SHARE_READ,
  164. NULL,
  165. OPEN_EXISTING,
  166. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  167. NULL);
  168. Error = GetLastError ();
  169. delete []pszReparseIndex;
  170. SetLastError (Error);
  171. return hReparseIndex;
  172. }
  173. HANDLE xOpenVolume(PCTSTR pcszVolume)
  174. {
  175. HANDLE hVolume = INVALID_HANDLE_VALUE;
  176. PTSTR pszVolumeName = NULL;
  177. DWORD Error = 0;
  178. pszVolumeName = new TCHAR[MAX_PATH];
  179. BOOL bResult = GetVolumeNameForVolumeMountPoint(
  180. pcszVolume,
  181. pszVolumeName,
  182. MAX_PATH);
  183. if (bResult)
  184. {
  185. hVolume = CreateFile(
  186. pszVolumeName,
  187. GENERIC_READ,
  188. FILE_SHARE_READ,
  189. NULL,
  190. OPEN_EXISTING,
  191. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  192. NULL);
  193. Error = GetLastError ();
  194. }
  195. else
  196. {
  197. Error = GetLastError ();
  198. }
  199. delete []pszVolumeName;
  200. SetLastError (Error);
  201. return hVolume;
  202. }
  203. BOOL xGetNextReparseRecord(
  204. HANDLE hIndex,
  205. PFILE_REPARSE_POINT_INFORMATION ReparseInfo)
  206. {
  207. BOOL bResult = FALSE;
  208. DWORD Error = 0;
  209. IO_STATUS_BLOCK ioStatus;
  210. NTSTATUS status = NtQueryDirectoryFile(hIndex,
  211. NULL,
  212. NULL,
  213. NULL,
  214. &ioStatus,
  215. ReparseInfo,
  216. sizeof(FILE_REPARSE_POINT_INFORMATION),
  217. FileReparsePointInformation,
  218. TRUE,
  219. NULL,
  220. FALSE);
  221. if (!NT_SUCCESS(status))
  222. {
  223. Error = RtlNtStatusToDosError(status);
  224. if(Error == ERROR_NO_MORE_FILES)
  225. {
  226. Error = 0;
  227. }
  228. bResult = TRUE;
  229. }
  230. SetLastError(Error);
  231. return bResult;
  232. }
  233. DWORD
  234. DeleteDirectory(LPWSTR VolumeName, LPWSTR pDfsDirectory)
  235. {
  236. DWORD Status = 0;
  237. DWORD BuffLen = 0;
  238. LPWSTR lpExistingFileName = NULL;
  239. UNICODE_STRING UnicodeFileName;
  240. BuffLen = (wcslen(L"\\??\\") + 1) * sizeof(WCHAR);
  241. BuffLen += ((wcslen((const wchar_t *)pDfsDirectory) + 1)* sizeof(WCHAR));
  242. BuffLen += ((wcslen((const wchar_t *)VolumeName) + 1)* sizeof(WCHAR));
  243. lpExistingFileName = (LPWSTR)HeapAlloc (GetProcessHeap(), 0, BuffLen);
  244. if(lpExistingFileName == NULL)
  245. {
  246. wprintf(L"Out of memory\n");
  247. Status = ERROR_NOT_ENOUGH_MEMORY;
  248. return Status;
  249. }
  250. wcscpy(lpExistingFileName, L"\\??\\");
  251. wcscat(lpExistingFileName, (const wchar_t *) VolumeName);
  252. wcscat(lpExistingFileName, (const wchar_t *) pDfsDirectory);
  253. UnicodeFileName.Buffer = lpExistingFileName ;
  254. UnicodeFileName.Length = wcslen(lpExistingFileName) * sizeof(WCHAR);
  255. UnicodeFileName.MaximumLength = UnicodeFileName.Length;
  256. Status = DeleteLinkReparsePoint( &UnicodeFileName,
  257. NULL);
  258. HeapFree(GetProcessHeap(), 0, lpExistingFileName);
  259. return Status;
  260. }
  261. DWORD DisplayFileName(
  262. PTSTR pszVolume,
  263. HANDLE hVolume,
  264. LONGLONG llFileId,
  265. BOOL fRemoveDirectory)
  266. {
  267. UNICODE_STRING usIdString;
  268. NTSTATUS status = 0;
  269. DWORD ErrorCode = 0;
  270. OBJECT_ATTRIBUTES ObjectAttributes;
  271. HANDLE hFile = INVALID_HANDLE_VALUE;
  272. IO_STATUS_BLOCK IoStatusBlock;
  273. struct {
  274. FILE_NAME_INFORMATION FileInformation;
  275. WCHAR FileName[MAX_PATH];
  276. } NameFile;
  277. fRemoveDirectory;
  278. ZeroMemory(
  279. &NameFile,
  280. sizeof(NameFile));
  281. usIdString.Length = sizeof(LONGLONG);
  282. usIdString.MaximumLength = sizeof(LONGLONG);
  283. usIdString.Buffer = (PWCHAR)&llFileId;
  284. InitializeObjectAttributes(
  285. &ObjectAttributes,
  286. &usIdString,
  287. OBJ_CASE_INSENSITIVE,
  288. hVolume,
  289. NULL); // security descriptor
  290. status = NtCreateFile(
  291. &hFile,
  292. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  293. &ObjectAttributes,
  294. &IoStatusBlock,
  295. NULL, // allocation size
  296. FILE_ATTRIBUTE_NORMAL,
  297. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  298. FILE_OPEN,
  299. FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_BY_FILE_ID,
  300. NULL, // EA buffer
  301. 0); // EA length
  302. if (NT_SUCCESS(status))
  303. {
  304. status = NtQueryInformationFile(
  305. hFile,
  306. &IoStatusBlock,
  307. &(NameFile.FileInformation),
  308. sizeof(NameFile),
  309. FileNameInformation);
  310. if (NT_SUCCESS(status))
  311. {
  312. wprintf(L"%ws%ws\n",pszVolume, NameFile.FileInformation.FileName+1);
  313. }
  314. else
  315. {
  316. ErrorCode = RtlNtStatusToDosError(status);
  317. SetLastError(ErrorCode);
  318. _tprintf(_T("Unable to query file name.\n"));
  319. }
  320. }
  321. else
  322. {
  323. ErrorCode = RtlNtStatusToDosError(status);
  324. SetLastError(ErrorCode);
  325. _tprintf(_T("Unable to open file by ID.\n"));
  326. }
  327. if (hFile!=INVALID_HANDLE_VALUE)
  328. {
  329. CloseHandle(hFile);
  330. }
  331. if((ErrorCode == 0) && fRemoveDirectory)
  332. {
  333. DeleteDirectory(pszVolume, NameFile.FileInformation.FileName+1);
  334. }
  335. return ErrorCode;
  336. }
  337. VOID
  338. CloseDirectory(
  339. HANDLE DirHandle )
  340. {
  341. NtClose( DirHandle );
  342. }
  343. NTSTATUS
  344. ClearDfsReparsePoint(
  345. IN HANDLE DirHandle )
  346. {
  347. NTSTATUS NtStatus = STATUS_SUCCESS;
  348. REPARSE_DATA_BUFFER ReparseDataBuffer;
  349. IO_STATUS_BLOCK IoStatusBlock;
  350. //
  351. // Attempt to set a reparse point on the directory
  352. //
  353. RtlZeroMemory( &ReparseDataBuffer, sizeof(ReparseDataBuffer) );
  354. ReparseDataBuffer.ReparseTag = IO_REPARSE_TAG_DFS;
  355. ReparseDataBuffer.ReparseDataLength = 0;
  356. NtStatus = NtFsControlFile( DirHandle,
  357. NULL,
  358. NULL,
  359. NULL,
  360. &IoStatusBlock,
  361. FSCTL_DELETE_REPARSE_POINT,
  362. &ReparseDataBuffer,
  363. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuffer.ReparseDataLength,
  364. NULL,
  365. 0 );
  366. return NtStatus;
  367. }
  368. NTSTATUS
  369. OpenDirectory(
  370. PUNICODE_STRING pDirectoryName,
  371. ULONG ShareMode,
  372. HANDLE RelativeHandle,
  373. PHANDLE pOpenedHandle,
  374. PBOOLEAN pIsNewlyCreated )
  375. {
  376. NTSTATUS NtStatus;
  377. OBJECT_ATTRIBUTES ObjectAttributes;
  378. ACCESS_MASK DesiredAccess;
  379. PLARGE_INTEGER AllocationSize;
  380. ULONG FileAttributes;
  381. ULONG CreateDisposition;
  382. ULONG CreateOptions;
  383. IO_STATUS_BLOCK IoStatusBlock;
  384. AllocationSize = NULL;
  385. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  386. CreateDisposition = FILE_OPEN_IF;
  387. CreateOptions = FILE_DIRECTORY_FILE |
  388. FILE_OPEN_REPARSE_POINT |
  389. FILE_SYNCHRONOUS_IO_NONALERT;
  390. DesiredAccess = FILE_READ_DATA |
  391. FILE_WRITE_DATA |
  392. FILE_READ_ATTRIBUTES |
  393. FILE_WRITE_ATTRIBUTES |
  394. SYNCHRONIZE;
  395. InitializeObjectAttributes (
  396. &ObjectAttributes,
  397. pDirectoryName, //Object Name
  398. 0, //Attributes
  399. RelativeHandle, //Root handle
  400. NULL); //Security descriptor.
  401. NtStatus = NtCreateFile(pOpenedHandle,
  402. DesiredAccess,
  403. &ObjectAttributes,
  404. &IoStatusBlock,
  405. AllocationSize,
  406. FileAttributes,
  407. ShareMode,
  408. CreateDisposition,
  409. CreateOptions,
  410. NULL, // EaBuffer
  411. 0 ); // EaLength
  412. if ( (NtStatus == STATUS_SUCCESS) && (pIsNewlyCreated != NULL) )
  413. {
  414. *pIsNewlyCreated = (IoStatusBlock.Information == FILE_CREATED)? TRUE : FALSE;
  415. }
  416. return NtStatus;
  417. }
  418. NTSTATUS
  419. IsDirectoryReparsePoint(
  420. IN HANDLE DirHandle,
  421. OUT PBOOLEAN pReparsePoint,
  422. OUT PBOOLEAN pDfsReparsePoint )
  423. {
  424. NTSTATUS NtStatus;
  425. FILE_BASIC_INFORMATION BasicInfo;
  426. IO_STATUS_BLOCK IoStatusBlock;
  427. //
  428. //we assume these are not reparse points.
  429. //
  430. *pReparsePoint = FALSE;
  431. *pDfsReparsePoint = FALSE;
  432. //
  433. // Query for the basic information, which has the attributes.
  434. //
  435. NtStatus = NtQueryInformationFile( DirHandle,
  436. &IoStatusBlock,
  437. (PVOID)&BasicInfo,
  438. sizeof(BasicInfo),
  439. FileBasicInformation );
  440. if (NtStatus == STATUS_SUCCESS)
  441. {
  442. //
  443. // If the attributes indicate reparse point, we have a reparse
  444. // point directory on our hands.
  445. //
  446. if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  447. {
  448. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  449. *pReparsePoint = TRUE;
  450. NtStatus = NtQueryInformationFile( DirHandle,
  451. &IoStatusBlock,
  452. (PVOID)&FileTagInformation,
  453. sizeof(FileTagInformation),
  454. FileAttributeTagInformation );
  455. if (NtStatus == STATUS_SUCCESS)
  456. {
  457. //
  458. // Checkif the tag indicates its a DFS reparse point,
  459. // and setup the return accordingly.
  460. //
  461. if (FileTagInformation.ReparseTag == IO_REPARSE_TAG_DFS)
  462. {
  463. *pDfsReparsePoint = TRUE;
  464. }
  465. }
  466. }
  467. }
  468. return NtStatus;
  469. }
  470. BOOLEAN
  471. IsEmptyDirectory(
  472. HANDLE DirectoryHandle,
  473. PVOID pDirectoryBuffer,
  474. ULONG DirectoryBufferSize )
  475. {
  476. NTSTATUS NtStatus;
  477. FILE_NAMES_INFORMATION *pFileInfo;
  478. ULONG NumberOfFiles = 1;
  479. BOOLEAN ReturnValue = FALSE;
  480. IO_STATUS_BLOCK IoStatus;
  481. NtStatus = NtQueryDirectoryFile ( DirectoryHandle,
  482. NULL, // no event
  483. NULL, // no apc routine
  484. NULL, // no apc context
  485. &IoStatus,
  486. pDirectoryBuffer,
  487. DirectoryBufferSize,
  488. FileNamesInformation,
  489. FALSE, // return single entry = false
  490. NULL, // filename
  491. FALSE ); // restart scan = false
  492. if (NtStatus == ERROR_SUCCESS)
  493. {
  494. pFileInfo = (FILE_NAMES_INFORMATION *)pDirectoryBuffer;
  495. while (pFileInfo->NextEntryOffset) {
  496. NumberOfFiles++;
  497. if (NumberOfFiles > 3)
  498. {
  499. break;
  500. }
  501. pFileInfo = (FILE_NAMES_INFORMATION *)((ULONG_PTR)(pFileInfo) +
  502. pFileInfo->NextEntryOffset);
  503. }
  504. if (NumberOfFiles <= 2)
  505. {
  506. ReturnValue = TRUE;
  507. }
  508. }
  509. return ReturnValue;
  510. }
  511. NTSTATUS
  512. DeleteLinkDirectories(
  513. PUNICODE_STRING pLinkName,
  514. HANDLE RelativeHandle )
  515. {
  516. UNICODE_STRING DirectoryToDelete = *pLinkName;
  517. NTSTATUS NtStatus = STATUS_SUCCESS;
  518. HANDLE CurrentDirectory = NULL;
  519. ULONG ShareMode = 0;
  520. OBJECT_ATTRIBUTES ObjectAttributes;
  521. ShareMode = FILE_SHARE_READ;
  522. //
  523. // dfsdev: fix this fixed size limit. it will hurt us in the future.
  524. //
  525. ULONG DirectoryBufferSize = 4096;
  526. PBYTE pDirectoryBuffer = new BYTE [DirectoryBufferSize];
  527. if (pDirectoryBuffer == NULL)
  528. {
  529. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  530. }
  531. // BUG 701594: Don't delete all directories under a reparse dir.
  532. // Just remove the reparse dir.
  533. if ( (NtStatus == STATUS_SUCCESS) && (DirectoryToDelete.Length != 0) )
  534. {
  535. NtStatus = OpenDirectory( &DirectoryToDelete,
  536. ShareMode,
  537. RelativeHandle,
  538. &CurrentDirectory,
  539. NULL );
  540. if (NtStatus == ERROR_SUCCESS)
  541. {
  542. if (IsEmptyDirectory(CurrentDirectory,
  543. pDirectoryBuffer,
  544. DirectoryBufferSize) == FALSE)
  545. {
  546. CloseDirectory( CurrentDirectory );
  547. }
  548. else
  549. {
  550. CloseDirectory( CurrentDirectory );
  551. InitializeObjectAttributes (
  552. &ObjectAttributes,
  553. &DirectoryToDelete,
  554. 0,
  555. RelativeHandle,
  556. NULL);
  557. NtStatus = NtDeleteFile( &ObjectAttributes );
  558. DebugInformation((L"Removed Directory %wZ, Status 0x%x\n",
  559. &DirectoryToDelete, NtStatus));
  560. }
  561. }
  562. }
  563. if (pDirectoryBuffer != NULL)
  564. {
  565. delete [] pDirectoryBuffer;
  566. }
  567. return NtStatus;
  568. }
  569. DWORD
  570. DeleteLinkReparsePoint(
  571. PUNICODE_STRING pDirectoryName,
  572. HANDLE ParentHandle )
  573. {
  574. NTSTATUS NtStatus = STATUS_SUCCESS;
  575. DWORD DosStatus = ERROR_SUCCESS;
  576. HANDLE LinkDirectoryHandle = INVALID_HANDLE_VALUE;
  577. BOOLEAN IsReparsePoint = FALSE;
  578. BOOLEAN IsDfsReparsePoint = FALSE;
  579. NtStatus = OpenDirectory( pDirectoryName,
  580. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  581. ParentHandle,
  582. &LinkDirectoryHandle,
  583. NULL );
  584. if (NtStatus == STATUS_SUCCESS)
  585. {
  586. NtStatus = IsDirectoryReparsePoint( LinkDirectoryHandle,
  587. &IsReparsePoint,
  588. &IsDfsReparsePoint );
  589. if ((NtStatus == STATUS_SUCCESS) &&
  590. (IsDfsReparsePoint == TRUE) )
  591. {
  592. NtStatus = ClearDfsReparsePoint( LinkDirectoryHandle );
  593. DosStatus = RtlNtStatusToDosError(NtStatus);
  594. wprintf(L"ClearDfsReparsePoint for %ws returned %x\n", pDirectoryName->Buffer, DosStatus);
  595. }
  596. else if(NtStatus != STATUS_SUCCESS)
  597. {
  598. DosStatus = RtlNtStatusToDosError(NtStatus);
  599. wprintf(L"Clearing DFS reparse point for %ws failed %x\n", pDirectoryName->Buffer, DosStatus);
  600. }
  601. else if(IsDfsReparsePoint == FALSE)
  602. {
  603. DosStatus = RtlNtStatusToDosError(NtStatus);
  604. wprintf(L"%ws does not have a DFS reparse point %x\n", pDirectoryName->Buffer, DosStatus);
  605. }
  606. NtClose( LinkDirectoryHandle );
  607. }
  608. else
  609. {
  610. NtStatus = RtlNtStatusToDosError(NtStatus);
  611. wprintf(L"Open for %ws returned %x\n", pDirectoryName->Buffer, NtStatus);
  612. }
  613. if (NtStatus == STATUS_SUCCESS)
  614. {
  615. NtStatus = DeleteLinkDirectories( pDirectoryName,
  616. NULL);
  617. }
  618. DosStatus = RtlNtStatusToDosError(NtStatus);
  619. return DosStatus;
  620. }
  621. DWORD
  622. DeleteReparsePoint(LPWSTR pDfsDirectory)
  623. {
  624. DWORD Status = 0;
  625. DWORD BuffLen = 0;
  626. LPWSTR lpExistingFileName = NULL;
  627. UNICODE_STRING UnicodeFileName;
  628. BuffLen = (wcslen(L"\\??\\") + 1) * sizeof(WCHAR);
  629. BuffLen += ((wcslen((const wchar_t *)pDfsDirectory) + 1)* sizeof(WCHAR));
  630. lpExistingFileName = (LPWSTR)HeapAlloc (GetProcessHeap(), 0, BuffLen);
  631. if(lpExistingFileName == NULL)
  632. {
  633. wprintf(L"Out of memory\n");
  634. Status = ERROR_NOT_ENOUGH_MEMORY;
  635. return Status;
  636. }
  637. wcscpy(lpExistingFileName, L"\\??\\");
  638. wcscat(lpExistingFileName, (const wchar_t *) pDfsDirectory);
  639. UnicodeFileName.Buffer = lpExistingFileName ;
  640. UnicodeFileName.Length = wcslen(lpExistingFileName) * sizeof(WCHAR);
  641. UnicodeFileName.MaximumLength = UnicodeFileName.Length;
  642. Status = DeleteLinkReparsePoint( &UnicodeFileName,
  643. NULL);
  644. HeapFree(GetProcessHeap(), 0, lpExistingFileName);
  645. return Status;
  646. }