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.

824 lines
24 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. common.c
  5. Abstract:
  6. This module contains common apis used by tlist & kill.
  7. Author:
  8. Wesley Witt (wesw) 20-May-1994
  9. Environment:
  10. User Mode
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include "common.h"
  16. BOOLEAN
  17. MassageLinkValue(
  18. IN LPCWSTR lpLinkName,
  19. IN LPCWSTR lpLinkValue,
  20. OUT PUNICODE_STRING NtLinkName,
  21. OUT PUNICODE_STRING NtLinkValue,
  22. OUT PUNICODE_STRING DosLinkValue
  23. )
  24. {
  25. PWSTR FilePart;
  26. PWSTR s, sBegin, sBackupLimit;
  27. NTSTATUS Status;
  28. USHORT nSaveNtNameLength;
  29. ULONG nLevels;
  30. //
  31. // Initialize output variables to NULL
  32. //
  33. RtlInitUnicodeString( NtLinkName, NULL );
  34. RtlInitUnicodeString( NtLinkValue, NULL );
  35. //
  36. // Translate link name into full NT path.
  37. //
  38. if (!RtlDosPathNameToNtPathName_U( lpLinkName,
  39. NtLinkName,
  40. NULL,
  41. NULL
  42. )
  43. ) {
  44. return FALSE;
  45. }
  46. //
  47. // All done if no link value.
  48. //
  49. if (!ARGUMENT_PRESENT( lpLinkValue )) {
  50. return TRUE;
  51. }
  52. //
  53. // If the target is a device, do not allow the link.
  54. //
  55. if (RtlIsDosDeviceName_U( (PWSTR)lpLinkValue )) {
  56. return FALSE;
  57. }
  58. //
  59. // Convert to DOS path to full path, and get Nt representation
  60. // of DOS path.
  61. //
  62. if (!RtlGetFullPathName_U( lpLinkValue,
  63. DosLinkValue->MaximumLength,
  64. DosLinkValue->Buffer,
  65. NULL
  66. )
  67. ) {
  68. return FALSE;
  69. }
  70. DosLinkValue->Length = wcslen( DosLinkValue->Buffer ) * sizeof( WCHAR );
  71. //
  72. // Verify that the link value is a valid NT name.
  73. //
  74. if (!RtlDosPathNameToNtPathName_U( DosLinkValue->Buffer,
  75. NtLinkValue,
  76. NULL,
  77. NULL
  78. )
  79. ) {
  80. return FALSE;
  81. }
  82. return TRUE;
  83. }
  84. BOOL
  85. CreateSymbolicLinkW(
  86. LPCWSTR lpLinkName,
  87. LPCWSTR lpLinkValue,
  88. BOOLEAN IsMountPoint,
  89. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  90. )
  91. /*++
  92. Routine Description:
  93. A symbolic link is established using CreateSymbolicLink.
  94. Arguments:
  95. lpLinkName - Supplies the DOS file name where the symbolic link is desired. This
  96. name must not exists as a file/directory.
  97. lpLinkValue - Points to an DOS name which is the value of the symbolic link. This
  98. name may or may not exist.
  99. lpSecurityAttributes - Points to a SECURITY_ATTRIBUTES structure that specifies
  100. the security attributes for the directory to be created. The file system must
  101. support this parameter for it to have an effect.
  102. Return Value:
  103. TRUE - The operation was successful.
  104. FALSE/NULL - The operation failed. Extended error status is available
  105. using GetLastError.
  106. --*/
  107. {
  108. NTSTATUS Status;
  109. BOOLEAN TranslationStatus;
  110. UNICODE_STRING NtLinkName;
  111. UNICODE_STRING NtLinkValue;
  112. UNICODE_STRING DosLinkValue;
  113. OBJECT_ATTRIBUTES ObjectAttributes;
  114. IO_STATUS_BLOCK IoStatusBlock;
  115. HANDLE FileHandle;
  116. ULONG FileAttributes;
  117. ULONG OpenOptions;
  118. ULONG ReparseDataLength;
  119. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  120. WCHAR FullPathLinkValue[ DOS_MAX_PATH_LENGTH+1 ];
  121. //
  122. // Ensure that both names were passed.
  123. //
  124. if (!ARGUMENT_PRESENT( lpLinkName ) || !ARGUMENT_PRESENT( lpLinkValue )) {
  125. SetLastError( ERROR_INVALID_NAME );
  126. return FALSE;
  127. }
  128. //
  129. // Convert link name and value paths into NT versions
  130. //
  131. DosLinkValue.Buffer = FullPathLinkValue;
  132. DosLinkValue.MaximumLength = sizeof( FullPathLinkValue );
  133. DosLinkValue.Length = 0;
  134. if (!MassageLinkValue( lpLinkName,
  135. lpLinkValue,
  136. &NtLinkName,
  137. &NtLinkValue,
  138. &DosLinkValue
  139. )
  140. ) {
  141. if (DosLinkValue.Length == 0) {
  142. SetLastError( ERROR_INVALID_NAME );
  143. }
  144. else {
  145. SetLastError( ERROR_PATH_NOT_FOUND );
  146. }
  147. RtlFreeUnicodeString( &NtLinkName );
  148. RtlFreeUnicodeString( &NtLinkValue );
  149. return FALSE;
  150. }
  151. InitializeObjectAttributes( &ObjectAttributes,
  152. &NtLinkName,
  153. OBJ_CASE_INSENSITIVE,
  154. NULL,
  155. NULL
  156. );
  157. if (ARGUMENT_PRESENT( lpSecurityAttributes )) {
  158. ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  159. }
  160. //
  161. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior.
  162. //
  163. OpenOptions = FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE;
  164. //
  165. // Open link name. Must NOT exist.
  166. //
  167. Status = NtCreateFile( &FileHandle,
  168. FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES |
  169. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  170. &ObjectAttributes,
  171. &IoStatusBlock,
  172. NULL,
  173. FILE_ATTRIBUTE_NORMAL,
  174. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  175. FILE_CREATE,
  176. OpenOptions,
  177. NULL,
  178. 0
  179. );
  180. //
  181. // Free the buffer for the link name as we are done with it.
  182. //
  183. RtlFreeUnicodeString( &NtLinkName );
  184. if (!NT_SUCCESS( Status )) {
  185. SetLastError( ERROR_INVALID_NAME );
  186. RtlFreeUnicodeString( &NtLinkValue );
  187. return FALSE;
  188. }
  189. //
  190. // Allocate a buffer to set the reparse point.
  191. //
  192. ReparseDataLength = (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
  193. REPARSE_DATA_BUFFER_HEADER_SIZE) +
  194. NtLinkValue.Length + sizeof(UNICODE_NULL) +
  195. DosLinkValue.Length + sizeof(UNICODE_NULL);
  196. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)
  197. RtlAllocateHeap( RtlProcessHeap(),
  198. HEAP_ZERO_MEMORY,
  199. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength
  200. );
  201. if (ReparseBufferHeader == NULL) {
  202. NtClose( FileHandle );
  203. RtlFreeUnicodeString( &NtLinkValue );
  204. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  205. return FALSE;
  206. }
  207. //
  208. // Set the reparse point with symbolic link tag.
  209. //
  210. if (IsMountPoint) {
  211. ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  212. }
  213. else {
  214. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  215. // No support for symbolic links in NT 5.0 Beta 1
  216. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  217. //
  218. // ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_SYMBOLIC_LINK;
  219. //
  220. SetLastError( ERROR_INVALID_PARAMETER );
  221. return FALSE;
  222. }
  223. ReparseBufferHeader->ReparseDataLength = (USHORT)ReparseDataLength;
  224. ReparseBufferHeader->Reserved = 0;
  225. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
  226. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength = NtLinkValue.Length;
  227. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset = NtLinkValue.Length + sizeof( UNICODE_NULL );
  228. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength = NtLinkValue.Length;
  229. RtlCopyMemory( ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer,
  230. NtLinkValue.Buffer,
  231. NtLinkValue.Length
  232. );
  233. RtlCopyMemory( (PCHAR)(ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer)+
  234. NtLinkValue.Length + sizeof(UNICODE_NULL),
  235. DosLinkValue.Buffer,
  236. DosLinkValue.Length
  237. );
  238. RtlFreeUnicodeString( &NtLinkValue );
  239. Status = NtFsControlFile( FileHandle,
  240. NULL,
  241. NULL,
  242. NULL,
  243. &IoStatusBlock,
  244. FSCTL_SET_REPARSE_POINT,
  245. ReparseBufferHeader,
  246. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength,
  247. NULL,
  248. 0
  249. );
  250. RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
  251. NtClose( FileHandle );
  252. if (!NT_SUCCESS( Status )) {
  253. return FALSE;
  254. }
  255. return TRUE;
  256. }
  257. BOOL
  258. SetSymbolicLinkW(
  259. LPCWSTR lpLinkName,
  260. LPCWSTR lpLinkValue
  261. )
  262. /*++
  263. Routine Description:
  264. A symbolic link is established using CreateSymbolicLink.
  265. Arguments:
  266. lpLinkName - Supplies the DOS file name where the symbolic link is located. This
  267. name must exist as a symbolic link to a file/directory.
  268. lpLinkValue - Points to an DOS name which is the value of the symbolic link. This
  269. name may or may not exist.
  270. Return Value:
  271. TRUE - The operation was successful.
  272. FALSE/NULL - The operation failed. Extended error status is available
  273. using GetLastError.
  274. --*/
  275. {
  276. NTSTATUS Status;
  277. BOOLEAN TranslationStatus;
  278. UNICODE_STRING NtLinkName;
  279. UNICODE_STRING NtLinkValue;
  280. UNICODE_STRING DosLinkValue;
  281. OBJECT_ATTRIBUTES ObjectAttributes;
  282. IO_STATUS_BLOCK IoStatusBlock;
  283. HANDLE FileHandle;
  284. ACCESS_MASK FileAccess;
  285. ULONG OpenOptions;
  286. ULONG ReparseDataLength;
  287. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  288. WCHAR FullPathLinkValue[ DOS_MAX_PATH_LENGTH+1 ];
  289. //
  290. // Ensure that link name was passed.
  291. //
  292. if (!ARGUMENT_PRESENT( lpLinkName )) {
  293. SetLastError( ERROR_INVALID_NAME );
  294. return FALSE;
  295. }
  296. //
  297. // Convert link name and value paths into NT versions
  298. //
  299. DosLinkValue.Buffer = FullPathLinkValue;
  300. DosLinkValue.MaximumLength = sizeof( FullPathLinkValue );
  301. DosLinkValue.Length = 0;
  302. if (!MassageLinkValue( lpLinkName,
  303. lpLinkValue,
  304. &NtLinkName,
  305. &NtLinkValue,
  306. &DosLinkValue
  307. )
  308. ) {
  309. if (DosLinkValue.Length == 0) {
  310. SetLastError( ERROR_INVALID_NAME );
  311. }
  312. else {
  313. SetLastError( ERROR_PATH_NOT_FOUND );
  314. }
  315. RtlFreeUnicodeString( &NtLinkName );
  316. RtlFreeUnicodeString( &NtLinkValue );
  317. return FALSE;
  318. }
  319. InitializeObjectAttributes( &ObjectAttributes,
  320. &NtLinkName,
  321. OBJ_CASE_INSENSITIVE,
  322. NULL,
  323. NULL
  324. );
  325. //
  326. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior.
  327. //
  328. OpenOptions = FILE_OPEN_FOR_BACKUP_INTENT |
  329. FILE_OPEN_REPARSE_POINT |
  330. FILE_SYNCHRONOUS_IO_NONALERT |
  331. FILE_NON_DIRECTORY_FILE;
  332. //
  333. // If no link value specified, then deleting the link
  334. //
  335. if (!ARGUMENT_PRESENT( lpLinkValue )) {
  336. FileAccess = DELETE | SYNCHRONIZE;
  337. }
  338. else {
  339. FileAccess = FILE_WRITE_DATA | FILE_READ_ATTRIBUTES |
  340. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE;
  341. }
  342. //
  343. // Open link name. Must exists.
  344. //
  345. Status = NtOpenFile( &FileHandle,
  346. FileAccess,
  347. &ObjectAttributes,
  348. &IoStatusBlock,
  349. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  350. OpenOptions
  351. );
  352. //
  353. // Free the buffer for the link name as we are done with it.
  354. //
  355. RtlFreeUnicodeString( &NtLinkName );
  356. if (!NT_SUCCESS( Status )) {
  357. RtlFreeUnicodeString( &NtLinkValue );
  358. SetLastError( ERROR_INVALID_NAME );
  359. return FALSE;
  360. }
  361. if (!ARGUMENT_PRESENT( lpLinkValue )) {
  362. FILE_DISPOSITION_INFORMATION Disposition;
  363. //
  364. // Delete the link
  365. //
  366. #undef DeleteFile
  367. Disposition.DeleteFile = TRUE;
  368. Status = NtSetInformationFile( FileHandle,
  369. &IoStatusBlock,
  370. &Disposition,
  371. sizeof( Disposition ),
  372. FileDispositionInformation
  373. );
  374. NtClose( FileHandle );
  375. if (!NT_SUCCESS( Status )) {
  376. return FALSE;
  377. }
  378. else {
  379. return TRUE;
  380. }
  381. }
  382. //
  383. // Allocate a buffer to set the reparse point.
  384. //
  385. ReparseDataLength = (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
  386. REPARSE_DATA_BUFFER_HEADER_SIZE) +
  387. NtLinkValue.Length + sizeof(UNICODE_NULL) +
  388. DosLinkValue.Length + sizeof(UNICODE_NULL);
  389. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)
  390. RtlAllocateHeap( RtlProcessHeap(),
  391. HEAP_ZERO_MEMORY,
  392. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength
  393. );
  394. if (ReparseBufferHeader == NULL) {
  395. RtlFreeUnicodeString( &NtLinkValue );
  396. NtClose( FileHandle );
  397. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  398. return FALSE;
  399. }
  400. //
  401. // Set the reparse point with symbolic link tag.
  402. //
  403. ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_SYMBOLIC_LINK;
  404. ReparseBufferHeader->ReparseDataLength = (USHORT)ReparseDataLength;
  405. ReparseBufferHeader->Reserved = 0;
  406. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
  407. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength = NtLinkValue.Length;
  408. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset = NtLinkValue.Length + sizeof( UNICODE_NULL );
  409. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength = NtLinkValue.Length;
  410. RtlCopyMemory( ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer,
  411. NtLinkValue.Buffer,
  412. NtLinkValue.Length
  413. );
  414. RtlCopyMemory( (PCHAR)(ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer)+
  415. NtLinkValue.Length + sizeof(UNICODE_NULL),
  416. DosLinkValue.Buffer,
  417. DosLinkValue.Length
  418. );
  419. RtlFreeUnicodeString( &NtLinkValue );
  420. Status = NtFsControlFile( FileHandle,
  421. NULL,
  422. NULL,
  423. NULL,
  424. &IoStatusBlock,
  425. FSCTL_SET_REPARSE_POINT,
  426. ReparseBufferHeader,
  427. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength,
  428. NULL,
  429. 0
  430. );
  431. RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
  432. NtClose( FileHandle );
  433. if (!NT_SUCCESS( Status )) {
  434. return FALSE;
  435. }
  436. return TRUE;
  437. }
  438. DWORD
  439. QuerySymbolicLinkW(
  440. LPCWSTR lpLinkName,
  441. LPWSTR lpBuffer,
  442. DWORD nBufferLength
  443. )
  444. /*++
  445. Routine Description:
  446. An existing file can be queried for its symbolic link value using QuerySymbolicLink.
  447. Arguments:
  448. lpLinkName - Supplies the file name of the file to be queried.
  449. lpBuffer - Points to a buffer where the symbolic link is to be returned.
  450. nBufferSize - Length of the buffer being passed by the caller.
  451. Return Value:
  452. If the function suceeds, the return value is the length, in characters, of the
  453. string copied to lpBuffer, not including the terminating null character. If the
  454. lpBuffer is too small, the return value is the size of the buffer, in characters,
  455. required to hold the name.
  456. Zero is returned if the operation failed. Extended error status is available
  457. using GetLastError.
  458. --*/
  459. {
  460. NTSTATUS Status;
  461. BOOLEAN TranslationStatus;
  462. UNICODE_STRING FileName;
  463. RTL_RELATIVE_NAME RelativeName;
  464. OBJECT_ATTRIBUTES ObjectAttributes;
  465. IO_STATUS_BLOCK IoStatusBlock;
  466. HANDLE FileHandle;
  467. ULONG OpenOptions;
  468. PWSTR pathBuffer;
  469. USHORT pathLength;
  470. USHORT NtPathLength;
  471. USHORT ReturnLength;
  472. PVOID FreeBuffer;
  473. REPARSE_DATA_BUFFER ReparseInfo;
  474. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  475. if (!ARGUMENT_PRESENT( lpLinkName )) {
  476. SetLastError( ERROR_INVALID_NAME );
  477. return 0;
  478. }
  479. TranslationStatus = RtlDosPathNameToNtPathName_U( lpLinkName,
  480. &FileName,
  481. NULL,
  482. &RelativeName
  483. );
  484. if (!TranslationStatus) {
  485. SetLastError( ERROR_PATH_NOT_FOUND );
  486. return 0;
  487. }
  488. FreeBuffer = FileName.Buffer;
  489. if (RelativeName.RelativeName.Length) {
  490. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  491. }
  492. else {
  493. RelativeName.ContainingDirectory = NULL;
  494. }
  495. InitializeObjectAttributes( &ObjectAttributes,
  496. &FileName,
  497. OBJ_CASE_INSENSITIVE,
  498. RelativeName.ContainingDirectory,
  499. NULL
  500. );
  501. //
  502. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior.
  503. //
  504. OpenOptions = FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT;
  505. //
  506. // Open as file for read access.
  507. //
  508. Status = NtOpenFile( &FileHandle,
  509. FILE_READ_DATA | SYNCHRONIZE,
  510. &ObjectAttributes,
  511. &IoStatusBlock,
  512. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  513. OpenOptions | FILE_NON_DIRECTORY_FILE
  514. );
  515. //
  516. // Free the buffer for the name as we are done with it.
  517. //
  518. RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer );
  519. if (!NT_SUCCESS( Status )) {
  520. SetLastError( ERROR_INVALID_NAME );
  521. return 0;
  522. }
  523. //
  524. // Query with zero length to get reparse point tag and required buffer length
  525. //
  526. Status = NtFsControlFile( FileHandle,
  527. NULL,
  528. NULL,
  529. NULL,
  530. &IoStatusBlock,
  531. FSCTL_GET_REPARSE_POINT,
  532. NULL,
  533. 0,
  534. (PVOID)&ReparseInfo,
  535. sizeof( ReparseInfo )
  536. );
  537. //
  538. // Verify that the reparse point buffer brings back a symbolic link or a
  539. // mount point, and that we got the required buffer length back via
  540. // IoStatus.Information
  541. //
  542. ReparseBufferHeader = NULL;
  543. if ((Status != STATUS_BUFFER_OVERFLOW) ||
  544. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  545. // No support for symbolic links in NT 5.0 Beta 1
  546. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  547. //
  548. // (ReparseInfo.ReparseTag != IO_REPARSE_TAG_SYMBOLIC_LINK) ||
  549. //
  550. (ReparseInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
  551. ) {
  552. Status = STATUS_OBJECT_NAME_INVALID;
  553. }
  554. else {
  555. //
  556. // Allocate a buffer to hold reparse point information
  557. //
  558. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)
  559. RtlAllocateHeap( RtlProcessHeap(),
  560. 0,
  561. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseInfo.ReparseDataLength
  562. );
  563. if (ReparseBufferHeader == NULL) {
  564. //
  565. // Not enough memory. Fail the call.
  566. //
  567. Status = STATUS_NO_MEMORY;
  568. }
  569. else {
  570. //
  571. // Now query the reparse point information into our allocated buffer.
  572. // This should not fail.
  573. //
  574. Status = NtFsControlFile( FileHandle,
  575. NULL,
  576. NULL,
  577. NULL,
  578. &IoStatusBlock,
  579. FSCTL_GET_REPARSE_POINT,
  580. NULL,
  581. 0,
  582. (PVOID)ReparseBufferHeader,
  583. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseInfo.ReparseDataLength
  584. );
  585. }
  586. }
  587. //
  588. // Done with file handle.
  589. //
  590. NtClose( FileHandle );
  591. //
  592. // Return any failure to caller
  593. //
  594. if (!NT_SUCCESS( Status )) {
  595. if (ReparseBufferHeader != NULL) {
  596. RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
  597. }
  598. return 0;
  599. }
  600. //
  601. // See if this is an old style symbolic link reparse point, which only stored the
  602. // NT path name. If so, return an error, as we dont have a DOS path to return
  603. //
  604. pathBuffer = (PWSTR)(
  605. (PCHAR)ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer +
  606. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset
  607. );
  608. pathLength = ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength;
  609. //
  610. // Sanity check the length. As the tag is fine we do not zero the buffer.
  611. //
  612. ReturnLength = pathLength / sizeof( WCHAR );
  613. //
  614. // If amount to return is less than callers buffer length, copy the Dos path
  615. // to the callers buffer
  616. //
  617. if (ReturnLength < nBufferLength) {
  618. RtlMoveMemory( (PUCHAR)lpBuffer,
  619. (PCHAR)pathBuffer,
  620. pathLength
  621. );
  622. }
  623. else {
  624. //
  625. // If we are failing for insufficient buffer length, tell them how much
  626. // space they really need including the terminating null character.
  627. //
  628. ReturnLength += 1;
  629. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  630. }
  631. RtlFreeHeap( RtlProcessHeap(), 0, ReparseBufferHeader );
  632. return ReturnLength;
  633. }
  634. VOID
  635. GetCommandLineArgs(
  636. LPDWORD NumberOfArguments,
  637. LPWSTR Arguments[]
  638. )
  639. {
  640. LPWSTR lpstrCmd;
  641. WCHAR ch;
  642. WCHAR ArgumentBuffer[ MAX_PATH ];
  643. LPWSTR p;
  644. lpstrCmd = GetCommandLine();
  645. // skip over program name
  646. do {
  647. ch = *lpstrCmd++;
  648. }
  649. while (ch != L' ' && ch != L'\t' && ch != L'\0');
  650. *NumberOfArguments = 0;
  651. while (ch != '\0') {
  652. // skip over any following white space
  653. while (ch != L'\0' && _istspace(ch)) {
  654. ch = *lpstrCmd++;
  655. }
  656. if (ch == L'\0') {
  657. break;
  658. }
  659. p = ArgumentBuffer;
  660. do {
  661. *p++ = ch;
  662. ch = *lpstrCmd++;
  663. } while (ch != L' ' && ch != L'\t' && ch != L'\0');
  664. *p = L'\0';
  665. Arguments[ *NumberOfArguments ] = malloc( (_tcslen( ArgumentBuffer ) + 1) * sizeof( WCHAR ) );
  666. if (Arguments[ *NumberOfArguments ]) {
  667. _tcscpy( Arguments[ *NumberOfArguments ], ArgumentBuffer );
  668. *NumberOfArguments += 1;
  669. }
  670. }
  671. return;
  672. }