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.

3732 lines
106 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pathmisc.c
  5. Abstract:
  6. Win32 misceleneous path functions
  7. Author:
  8. Mark Lucovsky (markl) 16-Oct-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "apcompat.h"
  13. #include <wow64t.h>
  14. BOOL
  15. IsThisARootDirectory(
  16. HANDLE RootHandle,
  17. PUNICODE_STRING FileName OPTIONAL
  18. )
  19. {
  20. PFILE_NAME_INFORMATION FileNameInfo;
  21. WCHAR Buffer[MAX_PATH+sizeof(FileNameInfo)];
  22. IO_STATUS_BLOCK IoStatusBlock;
  23. NTSTATUS Status;
  24. BOOL rv;
  25. OBJECT_ATTRIBUTES Attributes;
  26. HANDLE LinkHandle;
  27. WCHAR LinkValueBuffer[2*MAX_PATH];
  28. UNICODE_STRING LinkValue;
  29. ULONG ReturnedLength;
  30. rv = FALSE;
  31. FileNameInfo = (PFILE_NAME_INFORMATION)Buffer;
  32. if (RootHandle == NULL) {
  33. Status = STATUS_INVALID_HANDLE;
  34. } else {
  35. Status = NtQueryInformationFile (RootHandle,
  36. &IoStatusBlock,
  37. FileNameInfo,
  38. sizeof(Buffer),
  39. FileNameInformation);
  40. }
  41. if (NT_SUCCESS (Status)) {
  42. if ( FileNameInfo->FileName[(FileNameInfo->FileNameLength>>1)-1] == (WCHAR)'\\' ) {
  43. rv = TRUE;
  44. }
  45. }
  46. if ( !rv ) {
  47. //
  48. // See if this is a dos substed drive (or) redirected net drive
  49. //
  50. if (ARGUMENT_PRESENT (FileName)) {
  51. FileName->Length = FileName->Length - sizeof((WCHAR)'\\');
  52. InitializeObjectAttributes( &Attributes,
  53. FileName,
  54. OBJ_CASE_INSENSITIVE,
  55. NULL,
  56. NULL
  57. );
  58. Status = NtOpenSymbolicLinkObject (&LinkHandle,
  59. SYMBOLIC_LINK_QUERY,
  60. &Attributes);
  61. FileName->Length = FileName->Length + sizeof((WCHAR)'\\');
  62. if (NT_SUCCESS (Status)) {
  63. //
  64. // Now query the link and see if there is a redirection
  65. //
  66. LinkValue.Buffer = LinkValueBuffer;
  67. LinkValue.Length = 0;
  68. LinkValue.MaximumLength = (USHORT)(sizeof(LinkValueBuffer));
  69. ReturnedLength = 0;
  70. Status = NtQuerySymbolicLinkObject( LinkHandle,
  71. &LinkValue,
  72. &ReturnedLength
  73. );
  74. NtClose( LinkHandle );
  75. if ( NT_SUCCESS(Status) ) {
  76. rv = TRUE;
  77. }
  78. }
  79. }
  80. }
  81. return rv;
  82. }
  83. UINT
  84. APIENTRY
  85. GetSystemDirectoryA(
  86. LPSTR lpBuffer,
  87. UINT uSize
  88. )
  89. /*++
  90. Routine Description:
  91. ANSI thunk to GetSystemDirectoryW
  92. --*/
  93. {
  94. ANSI_STRING AnsiString;
  95. NTSTATUS Status;
  96. ULONG cbAnsiString;
  97. PUNICODE_STRING WindowsSystemDirectory = &BaseWindowsSystemDirectory;
  98. #ifdef WX86
  99. if (NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll) {
  100. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
  101. WindowsSystemDirectory = &BaseWindowsSys32x86Directory;
  102. }
  103. #endif
  104. // BaseWindowsSystemDirectory.Length contains the byte
  105. // count of unicode string.
  106. // Original code does "UnicodeLength / sizeof(WCHAR)" to
  107. // get the size of corresponding ansi string.
  108. // This is correct in SBCS environment. However in DBCS
  109. // environment, it's definitely WRONG.
  110. Status = RtlUnicodeToMultiByteSize(&cbAnsiString,
  111. WindowsSystemDirectory->Buffer,
  112. WindowsSystemDirectory->MaximumLength
  113. );
  114. if ( !NT_SUCCESS(Status) ) {
  115. return 0;
  116. }
  117. if ( (USHORT)uSize < (USHORT)cbAnsiString ) {
  118. return cbAnsiString;
  119. }
  120. AnsiString.MaximumLength = (USHORT)(uSize);
  121. AnsiString.Buffer = lpBuffer;
  122. Status = BasepUnicodeStringTo8BitString(
  123. &AnsiString,
  124. WindowsSystemDirectory,
  125. FALSE
  126. );
  127. if ( !NT_SUCCESS(Status) ) {
  128. return 0;
  129. }
  130. return AnsiString.Length;
  131. }
  132. UINT
  133. APIENTRY
  134. GetSystemDirectoryW(
  135. LPWSTR lpBuffer,
  136. UINT uSize
  137. )
  138. /*++
  139. Routine Description:
  140. This function obtains the pathname of the Windows system
  141. subdirectory. The system subdirectory contains such files as
  142. Windows libraries, drivers, and font files.
  143. The pathname retrieved by this function does not end with a
  144. backslash unless the system directory is the root directory. For
  145. example, if the system directory is named WINDOWS\SYSTEM on drive
  146. C:, the pathname of the system subdirectory retrieved by this
  147. function is C:\WINDOWS\SYSTEM.
  148. Arguments:
  149. lpBuffer - Points to the buffer that is to receive the
  150. null-terminated character string containing the pathname.
  151. uSize - Specifies the maximum size (in bytes) of the buffer. This
  152. value should be set to at least MAX_PATH to allow sufficient room in
  153. the buffer for the pathname.
  154. Return Value:
  155. The return value is the length of the string copied to lpBuffer, not
  156. including the terminating null character. If the return value is
  157. greater than uSize, the return value is the size of the buffer
  158. required to hold the pathname. The return value is zero if the
  159. function failed.
  160. --*/
  161. {
  162. PUNICODE_STRING WindowsSystemDirectory = &BaseWindowsSystemDirectory;
  163. #ifdef WX86
  164. if (NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll) {
  165. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
  166. WindowsSystemDirectory = &BaseWindowsSys32x86Directory;
  167. }
  168. #endif
  169. if ( uSize*2 < WindowsSystemDirectory->MaximumLength ) {
  170. return WindowsSystemDirectory->MaximumLength/2;
  171. }
  172. RtlMoveMemory(
  173. lpBuffer,
  174. WindowsSystemDirectory->Buffer,
  175. WindowsSystemDirectory->Length
  176. );
  177. lpBuffer[(WindowsSystemDirectory->Length>>1)] = UNICODE_NULL;
  178. return WindowsSystemDirectory->Length/2;
  179. }
  180. UINT
  181. APIENTRY
  182. GetSystemWindowsDirectoryA(
  183. LPSTR lpBuffer,
  184. UINT uSize
  185. )
  186. /*++
  187. Routine Description:
  188. ANSI thunk to GetSystemWindowsDirectoryW
  189. --*/
  190. {
  191. ANSI_STRING AnsiString;
  192. NTSTATUS Status;
  193. ULONG cbAnsiString;
  194. // BaseWindowsDirectory.Length contains the byte
  195. // count of unicode string.
  196. // Original code does "UnicodeLength / sizeof(WCHAR)" to
  197. // get the size of corresponding ansi string.
  198. // This is correct in SBCS environment. However in DBCS
  199. // environment, it's definitely WRONG.
  200. Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
  201. BaseWindowsDirectory.Buffer,
  202. BaseWindowsDirectory.MaximumLength);
  203. if ( !NT_SUCCESS(Status) ) {
  204. return 0;
  205. }
  206. if ( (USHORT)uSize < (USHORT)cbAnsiString ) {
  207. return cbAnsiString;
  208. }
  209. AnsiString.MaximumLength = (USHORT)(uSize);
  210. AnsiString.Buffer = lpBuffer;
  211. Status = BasepUnicodeStringTo8BitString(
  212. &AnsiString,
  213. &BaseWindowsDirectory,
  214. FALSE
  215. );
  216. if ( !NT_SUCCESS(Status) ) {
  217. return 0;
  218. }
  219. return AnsiString.Length;
  220. }
  221. UINT
  222. APIENTRY
  223. GetSystemWindowsDirectoryW(
  224. LPWSTR lpBuffer,
  225. UINT uSize
  226. )
  227. /*++
  228. Routine Description:
  229. This function obtains the pathname of the system Windows directory.
  230. Arguments:
  231. lpBuffer - Points to the buffer that is to receive the
  232. null-terminated character string containing the pathname.
  233. uSize - Specifies the maximum size (in wchars) of the buffer. This
  234. value should be set to at least MAX_PATH to allow sufficient room in
  235. the buffer for the pathname.
  236. Return Value:
  237. The return value is the length of the string copied to lpBuffer, not
  238. including the terminating null character. If the return value is
  239. greater than uSize, the return value is the size of the buffer
  240. required to hold the pathname. The return value is zero if the
  241. function failed.
  242. --*/
  243. {
  244. if ( uSize*2 < BaseWindowsDirectory.MaximumLength ) {
  245. return BaseWindowsDirectory.MaximumLength/2;
  246. }
  247. RtlMoveMemory(
  248. lpBuffer,
  249. BaseWindowsDirectory.Buffer,
  250. BaseWindowsDirectory.Length
  251. );
  252. lpBuffer[(BaseWindowsDirectory.Length>>1)] = UNICODE_NULL;
  253. return BaseWindowsDirectory.Length/2;
  254. }
  255. UINT
  256. APIENTRY
  257. GetSystemWow64DirectoryA(
  258. LPSTR lpBuffer,
  259. UINT uSize
  260. )
  261. /*++
  262. Routine Description:
  263. This function obtains the pathname of the system wow64 directory.
  264. Arguments:
  265. lpBuffer - Points to the buffer that is to receive the
  266. null-terminated character string containing the pathname.
  267. uSize - Specifies the maximum size (in bytes) of the buffer. This
  268. value should be set to at least MAX_PATH to allow sufficient room in
  269. the buffer for the pathname.
  270. Return Value:
  271. The return value is the length of the string copied to lpBuffer, not
  272. including the terminating null character. If the return value is
  273. greater than uSize, the return value is the size of the buffer
  274. required to hold the pathname. The return value is zero if the
  275. function failed.
  276. --*/
  277. {
  278. #if ! defined(BUILD_WOW6432) && ! defined(_WIN64)
  279. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  280. return 0;
  281. #else // BUILD_WOW6432 || _WIN64
  282. const CHAR syswowdir[] = "\\" WOW64_SYSTEM_DIRECTORY;
  283. UINT Available, Needed;
  284. if (uSize < sizeof(syswowdir)) {
  285. // We don't even have enough room to hold the syswow64
  286. // subdirectory component, much less the whole path. Pass in a
  287. // zero length so that we get back the length needed.
  288. Available = 0;
  289. } else {
  290. // We might have enough room; decrement the size passed in by the
  291. // amount of overhead we'll use.
  292. Available = uSize - sizeof(syswowdir) + 1 /* NULL compensation */;
  293. }
  294. Needed = GetSystemWindowsDirectoryA(lpBuffer, Available);
  295. if (Needed == 0) {
  296. // The call failed -- just return zero.
  297. return 0;
  298. }
  299. if (Needed <= Available) {
  300. // We had enough buffer space, even with our overhead; we can go
  301. // ahead and tack on the syswow64 directory name.
  302. RtlMoveMemory(lpBuffer + Needed,
  303. syswowdir,
  304. sizeof(syswowdir));
  305. }
  306. return (Needed + sizeof(syswowdir) - 1);
  307. #endif // BUILD_WOW6432 || _WIN64
  308. }
  309. UINT
  310. APIENTRY
  311. GetSystemWow64DirectoryW(
  312. LPWSTR lpBuffer,
  313. UINT uSize
  314. )
  315. /*++
  316. Routine Description:
  317. This function obtains the pathname of the system wow64 directory.
  318. Arguments:
  319. lpBuffer - Points to the buffer that is to receive the
  320. null-terminated character string containing the pathname.
  321. uSize - Specifies the maximum size (in wchars) of the buffer. This
  322. value should be set to at least MAX_PATH to allow sufficient room in
  323. the buffer for the pathname.
  324. Return Value:
  325. The return value is the length of the string copied to lpBuffer, not
  326. including the terminating null character. If the return value is
  327. greater than uSize, the return value is the size of the buffer
  328. required to hold the pathname. The return value is zero if the
  329. function failed.
  330. --*/
  331. {
  332. #if ! defined(BUILD_WOW6432) && ! defined(_WIN64)
  333. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  334. return 0;
  335. #else // BUILD_WOW6432 || _WIN64
  336. const WCHAR syswowdir[] = L"\\" WOW64_SYSTEM_DIRECTORY_U;
  337. UINT Available, Needed;
  338. const UINT SysWCharSize = sizeof(syswowdir) / sizeof(WCHAR);
  339. if (uSize < SysWCharSize) {
  340. // We don't even have enough room to hold the syswow64
  341. // subdirectory component, much less the whole path. Pass in a
  342. // zero length so that we get back the length needed.
  343. Available = 0;
  344. } else {
  345. // We might have enough room; decrement the size passed in by the
  346. // amount of overhead we'll use.
  347. Available = uSize - SysWCharSize + 1 /* NULL compensation */;
  348. }
  349. Needed = GetSystemWindowsDirectoryW(lpBuffer, Available);
  350. if (Needed == 0) {
  351. // The call failed -- just return zero.
  352. return 0;
  353. }
  354. if (Needed <= Available) {
  355. // We had enough buffer space, even with our overhead; we can go
  356. // ahead and tack on the syswow64 directory name.
  357. RtlMoveMemory(lpBuffer + Needed,
  358. syswowdir,
  359. sizeof(syswowdir));
  360. }
  361. return (Needed + SysWCharSize - 1);
  362. #endif // BUILD_WOW6432 || _WIN64
  363. }
  364. UINT
  365. APIENTRY
  366. GetWindowsDirectoryA(
  367. LPSTR lpBuffer,
  368. UINT uSize
  369. )
  370. /*++
  371. Routine Description:
  372. --*/
  373. {
  374. if (gpTermsrvGetWindowsDirectoryA) {
  375. //
  376. // If Terminal Server get the Per User Windows Directory
  377. //
  378. UINT retval;
  379. if (retval = gpTermsrvGetWindowsDirectoryA(lpBuffer, uSize)) {
  380. return retval;
  381. }
  382. }
  383. return GetSystemWindowsDirectoryA(lpBuffer,uSize);
  384. }
  385. UINT
  386. APIENTRY
  387. GetWindowsDirectoryW(
  388. LPWSTR lpBuffer,
  389. UINT uSize
  390. )
  391. /*++
  392. Routine Description:
  393. This function obtains the pathname of the Windows directory. The
  394. Windows directory contains such files as Windows applications,
  395. initialization files, and help files.
  396. 425
  397. The pathname retrieved by this function does not end with a
  398. backslash unless the Windows directory is the root directory. For
  399. example, if the Windows directory is named WINDOWS on drive C:, the
  400. pathname of the Windows directory retrieved by this function is
  401. C:\WINDOWS If Windows was installed in the root directory of drive
  402. C:, the pathname retrieved by this function is C:\
  403. Arguments:
  404. lpBuffer - Points to the buffer that is to receive the
  405. null-terminated character string containing the pathname.
  406. uSize - Specifies the maximum size (in bytes) of the buffer. This
  407. value should be set to at least MAX_PATH to allow sufficient room in
  408. the buffer for the pathname.
  409. Return Value:
  410. The return value is the length of the string copied to lpBuffer, not
  411. including the terminating null character. If the return value is
  412. greater than uSize, the return value is the size of the buffer
  413. required to hold the pathname. The return value is zero if the
  414. function failed.
  415. --*/
  416. {
  417. if (gpTermsrvGetWindowsDirectoryW) {
  418. //
  419. // If Terminal Server get the Per User Windows Directory
  420. //
  421. UINT retval;
  422. if (retval = gpTermsrvGetWindowsDirectoryW(lpBuffer, uSize)) {
  423. return retval;
  424. }
  425. }
  426. return GetSystemWindowsDirectoryW(lpBuffer,uSize);
  427. }
  428. UINT
  429. APIENTRY
  430. GetDriveTypeA(
  431. LPCSTR lpRootPathName
  432. )
  433. /*++
  434. Routine Description:
  435. ANSI thunk to GetDriveTypeW
  436. --*/
  437. {
  438. PUNICODE_STRING Unicode;
  439. LPCWSTR lpRootPathName_U;
  440. if (ARGUMENT_PRESENT(lpRootPathName)) {
  441. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  442. if (Unicode == NULL) {
  443. return 1;
  444. }
  445. lpRootPathName_U = (LPCWSTR)Unicode->Buffer;
  446. }
  447. else {
  448. lpRootPathName_U = NULL;
  449. }
  450. return GetDriveTypeW(lpRootPathName_U);
  451. }
  452. UINT
  453. APIENTRY
  454. GetDriveTypeW(
  455. LPCWSTR lpRootPathName
  456. )
  457. /*++
  458. Routine Description:
  459. This function determines whether a disk drive is removeable, fixed,
  460. remote, CD ROM, or a RAM disk.
  461. The return value is zero if the function cannot determine the drive
  462. type, or 1 if the specified root directory does not exist.
  463. Arguments:
  464. lpRootPathName - An optional parameter, that if specified, supplies
  465. the root directory of the disk whose drive type is to be
  466. determined. If this parameter is not specified, then the root
  467. of the current directory is used.
  468. Return Value:
  469. The return value specifies the type of drive. It can be one of the
  470. following values:
  471. DRIVE_UNKNOWN - The drive type can not be determined.
  472. DRIVE_NO_ROOT_DIR - The root directory does not exist.
  473. DRIVE_REMOVABLE - Disk can be removed from the drive.
  474. DRIVE_FIXED - Disk cannot be removed from the drive.
  475. DRIVE_REMOTE - Drive is a remote (network) drive.
  476. DRIVE_CDROM - Drive is a CD rom drive.
  477. DRIVE_RAMDISK - Drive is a RAM disk.
  478. --*/
  479. {
  480. WCHAR wch;
  481. ULONG n, DriveNumber;
  482. WCHAR DefaultPath[MAX_PATH];
  483. PWSTR RootPathName;
  484. NTSTATUS Status;
  485. OBJECT_ATTRIBUTES Obja;
  486. HANDLE Handle;
  487. UNICODE_STRING FileName, volumeNameString;
  488. IO_STATUS_BLOCK IoStatusBlock;
  489. BOOLEAN TranslationStatus;
  490. PVOID FreeBuffer;
  491. DWORD ReturnValue;
  492. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  493. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  494. WCHAR volumeName[MAX_PATH];
  495. if (!ARGUMENT_PRESENT(lpRootPathName)) {
  496. n = RtlGetCurrentDirectory_U(sizeof(DefaultPath), DefaultPath);
  497. RootPathName = DefaultPath;
  498. if (n > (3 * sizeof(WCHAR))) {
  499. RootPathName[3]=UNICODE_NULL;
  500. }
  501. }
  502. else
  503. if (lpRootPathName == (PWSTR)IntToPtr(0xFFFFFFFF)) {
  504. //
  505. // Hack to be compatible with undocumented feature of old
  506. // implementation.
  507. //
  508. return 0;
  509. }
  510. else {
  511. //
  512. // If input string is just C: then convert to C:\ so it does
  513. // not default to current directory which may or may not be
  514. // at the root.
  515. //
  516. RootPathName = (PWSTR)lpRootPathName;
  517. if (wcslen( RootPathName ) == 2) {
  518. wch = RtlUpcaseUnicodeChar( *RootPathName );
  519. if (wch >= (WCHAR)'A' &&
  520. wch <= (WCHAR)'Z' &&
  521. RootPathName[1] == (WCHAR)':'
  522. ) {
  523. RootPathName = wcscpy(DefaultPath, lpRootPathName);
  524. RootPathName[2] = (WCHAR)'\\';
  525. RootPathName[3] = UNICODE_NULL;
  526. }
  527. }
  528. }
  529. //
  530. // If input string is of the form C:\ then look in the drive letter
  531. // cache maintained by the kernel to see if the drive type is already
  532. // known.
  533. //
  534. wch = RtlUpcaseUnicodeChar( *RootPathName );
  535. if (wch >= (WCHAR)'A' &&
  536. wch <= (WCHAR)'Z' &&
  537. RootPathName[1]==(WCHAR)':' &&
  538. RootPathName[2]==(WCHAR)'\\' &&
  539. RootPathName[3]==UNICODE_NULL
  540. ) {
  541. Status = NtQueryInformationProcess( NtCurrentProcess(),
  542. ProcessDeviceMap,
  543. &ProcessDeviceMapInfo.Query,
  544. sizeof( ProcessDeviceMapInfo.Query ),
  545. NULL
  546. );
  547. if (!NT_SUCCESS( Status )) {
  548. RtlZeroMemory( &ProcessDeviceMapInfo, sizeof( ProcessDeviceMapInfo ) );
  549. }
  550. DriveNumber = wch - (WCHAR)'A';
  551. if (ProcessDeviceMapInfo.Query.DriveMap & (1 << DriveNumber)) {
  552. switch ( ProcessDeviceMapInfo.Query.DriveType[ DriveNumber ] ) {
  553. case DOSDEVICE_DRIVE_UNKNOWN:
  554. return DRIVE_UNKNOWN;
  555. case DOSDEVICE_DRIVE_REMOVABLE:
  556. return DRIVE_REMOVABLE;
  557. case DOSDEVICE_DRIVE_FIXED:
  558. return DRIVE_FIXED;
  559. case DOSDEVICE_DRIVE_REMOTE:
  560. return DRIVE_REMOTE;
  561. case DOSDEVICE_DRIVE_CDROM:
  562. return DRIVE_CDROM;
  563. case DOSDEVICE_DRIVE_RAMDISK:
  564. return DRIVE_RAMDISK;
  565. }
  566. }
  567. }
  568. //
  569. // Either not C:\ or kernel does not know the drive type, so try to
  570. // calculate the drive type by opening the root directory and doing
  571. // a query volume information.
  572. //
  573. //
  574. // If curdir is a UNC connection, and default path is used,
  575. // the RtlGetCurrentDirectory logic is wrong, so throw it away.
  576. //
  577. if (!ARGUMENT_PRESENT(lpRootPathName)) {
  578. RootPathName = L"\\";
  579. }
  580. TranslationStatus = RtlDosPathNameToNtPathName_U( RootPathName,
  581. &FileName,
  582. NULL,
  583. NULL
  584. );
  585. if (!TranslationStatus) {
  586. return DRIVE_NO_ROOT_DIR;
  587. }
  588. FreeBuffer = FileName.Buffer;
  589. //
  590. // Check to make sure a root was specified
  591. //
  592. if (FileName.Buffer[(FileName.Length >> 1)-1] != '\\') {
  593. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  594. return DRIVE_NO_ROOT_DIR;
  595. }
  596. FileName.Length -= 2;
  597. InitializeObjectAttributes( &Obja,
  598. &FileName,
  599. OBJ_CASE_INSENSITIVE,
  600. NULL,
  601. NULL
  602. );
  603. //
  604. // Open the file
  605. //
  606. Status = NtOpenFile( &Handle,
  607. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  608. &Obja,
  609. &IoStatusBlock,
  610. FILE_SHARE_READ | FILE_SHARE_WRITE,
  611. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  612. );
  613. //
  614. //
  615. // substd drives are really directories, so if we are dealing with one
  616. // of them, bypass this
  617. //
  618. if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
  619. if (BasepGetVolumeNameFromReparsePoint(lpRootPathName, volumeName,
  620. MAX_PATH, NULL)) {
  621. RtlInitUnicodeString(&volumeNameString, volumeName);
  622. volumeNameString.Buffer[1] = '?';
  623. volumeNameString.Length -= sizeof(WCHAR);
  624. InitializeObjectAttributes( &Obja,
  625. &volumeNameString,
  626. OBJ_CASE_INSENSITIVE,
  627. NULL,
  628. NULL
  629. );
  630. }
  631. Status = NtOpenFile(
  632. &Handle,
  633. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  634. &Obja,
  635. &IoStatusBlock,
  636. FILE_SHARE_READ | FILE_SHARE_WRITE,
  637. FILE_SYNCHRONOUS_IO_NONALERT
  638. );
  639. }
  640. else {
  641. //
  642. // check for substed drives another way just in case
  643. //
  644. FileName.Length = FileName.Length + sizeof((WCHAR)'\\');
  645. if (!IsThisARootDirectory(NULL,&FileName) ) {
  646. FileName.Length = FileName.Length - sizeof((WCHAR)'\\');
  647. if (NT_SUCCESS(Status)) {
  648. NtClose(Handle);
  649. }
  650. Status = NtOpenFile(
  651. &Handle,
  652. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  653. &Obja,
  654. &IoStatusBlock,
  655. FILE_SHARE_READ | FILE_SHARE_WRITE,
  656. FILE_SYNCHRONOUS_IO_NONALERT
  657. );
  658. }
  659. }
  660. RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer );
  661. if (!NT_SUCCESS( Status )) {
  662. return DRIVE_NO_ROOT_DIR;
  663. }
  664. //
  665. // Determine if this is a network or disk file system. If it
  666. // is a disk file system determine if this is removable or not
  667. //
  668. Status = NtQueryVolumeInformationFile( Handle,
  669. &IoStatusBlock,
  670. &DeviceInfo,
  671. sizeof(DeviceInfo),
  672. FileFsDeviceInformation
  673. );
  674. if (!NT_SUCCESS( Status )) {
  675. ReturnValue = DRIVE_UNKNOWN;
  676. }
  677. else
  678. if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) {
  679. ReturnValue = DRIVE_REMOTE;
  680. }
  681. else {
  682. switch (DeviceInfo.DeviceType) {
  683. case FILE_DEVICE_NETWORK:
  684. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  685. ReturnValue = DRIVE_REMOTE;
  686. break;
  687. case FILE_DEVICE_CD_ROM:
  688. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  689. ReturnValue = DRIVE_CDROM;
  690. break;
  691. case FILE_DEVICE_VIRTUAL_DISK:
  692. ReturnValue = DRIVE_RAMDISK;
  693. break;
  694. case FILE_DEVICE_DISK:
  695. case FILE_DEVICE_DISK_FILE_SYSTEM:
  696. if ( DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA ) {
  697. ReturnValue = DRIVE_REMOVABLE;
  698. }
  699. else {
  700. ReturnValue = DRIVE_FIXED;
  701. }
  702. break;
  703. default:
  704. ReturnValue = DRIVE_UNKNOWN;
  705. break;
  706. }
  707. }
  708. NtClose( Handle );
  709. return ReturnValue;
  710. }
  711. DWORD
  712. APIENTRY
  713. SearchPathA(
  714. LPCSTR lpPath,
  715. LPCSTR lpFileName,
  716. LPCSTR lpExtension,
  717. DWORD nBufferLength,
  718. LPSTR lpBuffer,
  719. LPSTR *lpFilePart
  720. )
  721. /*++
  722. Routine Description:
  723. ANSI thunk to SearchPathW
  724. --*/
  725. {
  726. UNICODE_STRING xlpPath;
  727. PUNICODE_STRING Unicode;
  728. UNICODE_STRING xlpExtension;
  729. PWSTR xlpBuffer;
  730. DWORD ReturnValue;
  731. ANSI_STRING AnsiString;
  732. UNICODE_STRING UnicodeString;
  733. NTSTATUS Status;
  734. PWSTR FilePart;
  735. PWSTR *FilePartPtr;
  736. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  737. FilePartPtr = &FilePart;
  738. }
  739. else {
  740. FilePartPtr = NULL;
  741. }
  742. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  743. if (Unicode == NULL) {
  744. return 0;
  745. }
  746. if ( ARGUMENT_PRESENT(lpExtension) ) {
  747. if (!Basep8BitStringToDynamicUnicodeString( &xlpExtension, lpExtension )) {
  748. return 0;
  749. }
  750. } else {
  751. xlpExtension.Buffer = NULL;
  752. }
  753. if ( ARGUMENT_PRESENT(lpPath) ) {
  754. if (!Basep8BitStringToDynamicUnicodeString( &xlpPath, lpPath )) {
  755. if ( ARGUMENT_PRESENT(lpExtension) ) {
  756. RtlFreeUnicodeString(&xlpExtension);
  757. }
  758. return 0;
  759. }
  760. } else {
  761. xlpPath.Buffer = NULL;
  762. }
  763. xlpBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nBufferLength<<1);
  764. if ( !xlpBuffer ) {
  765. BaseSetLastNTError(STATUS_NO_MEMORY);
  766. ReturnValue = 0;
  767. goto bail0;
  768. }
  769. ReturnValue = SearchPathW(
  770. xlpPath.Buffer,
  771. Unicode->Buffer,
  772. xlpExtension.Buffer,
  773. nBufferLength,
  774. xlpBuffer,
  775. FilePartPtr
  776. );
  777. //
  778. // === DBCS modification note [takaok] ===
  779. //
  780. // SearchPathW retruns:
  781. //
  782. // buffer size needed(including null terminator) if buffer size is too small.
  783. // number of characters( not including null terminator) if buffer size is enougth
  784. //
  785. // This means SearchPathW never returns value which is equal to nBufferLength.
  786. //
  787. if ( ReturnValue > nBufferLength ) {
  788. //
  789. // To know the ansi buffer size needed, we should get all of
  790. // unicode string.
  791. //
  792. RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
  793. xlpBuffer = RtlAllocateHeap(RtlProcessHeap(),
  794. MAKE_TAG( TMP_TAG ),
  795. ReturnValue * sizeof(WCHAR));
  796. if ( !xlpBuffer ) {
  797. BaseSetLastNTError(STATUS_NO_MEMORY);
  798. goto bail0;
  799. }
  800. ReturnValue = SearchPathW(
  801. xlpPath.Buffer,
  802. Unicode->Buffer,
  803. xlpExtension.Buffer,
  804. ReturnValue,
  805. xlpBuffer,
  806. FilePartPtr
  807. );
  808. if ( ReturnValue > 0 ) {
  809. //
  810. // We called SearchPathW with the enough size of buffer.
  811. // So, ReturnValue is the size of the path not including the
  812. // terminating null character.
  813. //
  814. Status = RtlUnicodeToMultiByteSize( &ReturnValue,
  815. xlpBuffer,
  816. ReturnValue * sizeof(WCHAR));
  817. if ( !NT_SUCCESS(Status) ) {
  818. BaseSetLastNTError(Status);
  819. ReturnValue = 0;
  820. }
  821. else {
  822. ReturnValue += 1;
  823. }
  824. }
  825. } else if ( ReturnValue > 0 ) {
  826. INT AnsiByteCount;
  827. //
  828. // We have unicode string. We need to compute the ansi byte count
  829. // of the string.
  830. //
  831. // ReturnValue : unicode character count not including null terminator
  832. // AnsiByteCount : ansi byte count not including null terminator
  833. //
  834. Status = RtlUnicodeToMultiByteSize( &AnsiByteCount,
  835. xlpBuffer,
  836. ReturnValue * sizeof(WCHAR) );
  837. if ( !NT_SUCCESS(Status) ) {
  838. BaseSetLastNTError(Status);
  839. ReturnValue = 0;
  840. }
  841. else {
  842. if ( AnsiByteCount < (INT)nBufferLength ) {
  843. //
  844. // The string (including null terminator) fits to the buffer
  845. //
  846. Status = RtlUnicodeToMultiByteN ( lpBuffer,
  847. nBufferLength - 1,
  848. &AnsiByteCount,
  849. xlpBuffer,
  850. ReturnValue * sizeof(WCHAR)
  851. );
  852. if ( !NT_SUCCESS(Status) ) {
  853. BaseSetLastNTError(Status);
  854. ReturnValue = 0;
  855. }
  856. else {
  857. lpBuffer[ AnsiByteCount ] = '\0';
  858. //
  859. // The return value is the byte count copied to the buffer
  860. // not including the terminating null character.
  861. //
  862. ReturnValue = AnsiByteCount;
  863. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  864. if ( FilePart == NULL ) {
  865. *lpFilePart = NULL;
  866. } else {
  867. INT PrefixLength;
  868. PrefixLength = (INT)(FilePart - xlpBuffer);
  869. Status = RtlUnicodeToMultiByteSize( &PrefixLength,
  870. xlpBuffer,
  871. PrefixLength * sizeof(WCHAR));
  872. if ( !NT_SUCCESS(Status) ) {
  873. BaseSetLastNTError(Status);
  874. ReturnValue = 0;
  875. }
  876. else {
  877. *lpFilePart = lpBuffer + PrefixLength;
  878. }
  879. }
  880. }
  881. }
  882. } else {
  883. //
  884. // We should return the size of the buffer required to
  885. // hold the path. The size should include the
  886. // terminating null character.
  887. //
  888. ReturnValue = AnsiByteCount + 1;
  889. }
  890. }
  891. }
  892. RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
  893. bail0:
  894. if ( ARGUMENT_PRESENT(lpExtension) ) {
  895. RtlFreeUnicodeString(&xlpExtension);
  896. }
  897. if ( ARGUMENT_PRESENT(lpPath) ) {
  898. RtlFreeUnicodeString(&xlpPath);
  899. }
  900. return ReturnValue;
  901. }
  902. #ifdef WX86
  903. ULONG
  904. GetFullPathNameWithWx86Override(
  905. PCWSTR lpFileName,
  906. ULONG nBufferLength,
  907. PWSTR lpBuffer,
  908. PWSTR *lpFilePart
  909. )
  910. {
  911. UNICODE_STRING FullPathName, PathUnicode, Wx86PathName;
  912. PUNICODE_STRING FoundFileName;
  913. RTL_PATH_TYPE PathType;
  914. PWSTR FilePart;
  915. ULONG Length, LengthPath;
  916. ULONG PathNameLength;
  917. FullPathName.Buffer = NULL;
  918. Wx86PathName.Buffer = NULL;
  919. if (lpFilePart) {
  920. *lpFilePart = NULL;
  921. }
  922. FullPathName.MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR)) + sizeof(WCHAR);
  923. FullPathName.Length = 0;
  924. FullPathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  925. MAKE_TAG( TMP_TAG ),
  926. FullPathName.MaximumLength
  927. );
  928. if (!FullPathName.Buffer) {
  929. PathNameLength = 0;
  930. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  931. goto WDOExitCleanup;
  932. }
  933. FoundFileName = &FullPathName;
  934. PathNameLength = RtlGetFullPathName_U(lpFileName,
  935. FullPathName.MaximumLength,
  936. FullPathName.Buffer,
  937. &FilePart
  938. );
  939. if (!PathNameLength || PathNameLength >= FullPathName.MaximumLength) {
  940. PathNameLength = 0;
  941. goto WDOExitCleanup;
  942. }
  943. FullPathName.Length = (USHORT)PathNameLength;
  944. PathUnicode = FullPathName;
  945. PathUnicode.Length = (USHORT)((ULONG_PTR)FilePart -
  946. (ULONG_PTR)FullPathName.Buffer);
  947. PathUnicode.Length -= sizeof(WCHAR);
  948. if (!RtlEqualUnicodeString(&PathUnicode, &BaseWindowsSystemDirectory, TRUE)) {
  949. goto WDOExitCleanup;
  950. }
  951. Wx86PathName.MaximumLength = BaseWindowsSys32x86Directory.Length +
  952. FullPathName.Length - PathUnicode.Length +
  953. 2*sizeof(WCHAR);
  954. Wx86PathName.Length = 0;
  955. Wx86PathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  956. MAKE_TAG( TMP_TAG ),
  957. Wx86PathName.MaximumLength
  958. );
  959. if (!Wx86PathName.Buffer) {
  960. goto WDOExitCleanup;
  961. }
  962. RtlCopyUnicodeString(&Wx86PathName, &BaseWindowsSys32x86Directory);
  963. Length = Wx86PathName.Length + sizeof(WCHAR);
  964. RtlAppendUnicodeToString (&Wx86PathName, FilePart - 1);
  965. if (RtlDoesFileExists_U(Wx86PathName.Buffer)) {
  966. FoundFileName = &Wx86PathName;
  967. FilePart = Wx86PathName.Buffer + Length/sizeof(WCHAR);
  968. }
  969. WDOExitCleanup:
  970. if (PathNameLength) {
  971. if (FoundFileName->Length >= nBufferLength) {
  972. PathNameLength = FoundFileName->Length + sizeof(WCHAR);
  973. }
  974. else {
  975. RtlMoveMemory(lpBuffer,
  976. FoundFileName->Buffer,
  977. FoundFileName->Length + sizeof(WCHAR)
  978. );
  979. PathNameLength = FoundFileName->Length;
  980. Length = (ULONG)(FilePart - FoundFileName->Buffer);
  981. if (lpFilePart) {
  982. *lpFilePart = lpBuffer + Length/sizeof(WCHAR);
  983. }
  984. }
  985. }
  986. if (FullPathName.Buffer) {
  987. RtlFreeHeap(RtlProcessHeap(), 0, FullPathName.Buffer);
  988. }
  989. if (Wx86PathName.Buffer) {
  990. RtlFreeHeap(RtlProcessHeap(), 0, Wx86PathName.Buffer);
  991. }
  992. return PathNameLength;
  993. }
  994. #endif
  995. DWORD
  996. APIENTRY
  997. SearchPathW(
  998. LPCWSTR lpPath,
  999. LPCWSTR lpFileName,
  1000. LPCWSTR lpExtension,
  1001. DWORD nBufferLength,
  1002. LPWSTR lpBuffer,
  1003. LPWSTR *lpFilePart
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This function is used to search for a file specifying a search path
  1008. and a filename. It returns with a fully qualified pathname of the
  1009. found file.
  1010. This function is used to locate a file using the specified path. If
  1011. the file is found, its fully qualified pathname is returned. In
  1012. addition to this, it calculates the address of the file name portion
  1013. of the fully qualified pathname.
  1014. Arguments:
  1015. lpPath - An optional parameter, that if specified, supplies the
  1016. search path to be used when locating the file. If this
  1017. parameter is not specified, the default windows search path is
  1018. used. The default path is:
  1019. - The current directory
  1020. - The windows directory
  1021. - The windows system directory
  1022. - The directories listed in the path environment variable
  1023. lpFileName - Supplies the file name of the file to search for.
  1024. lpExtension - An optional parameter, that if specified, supplies an
  1025. extension to be added to the filename when doing the search.
  1026. The extension is only added if the specified filename does not
  1027. end with an extension.
  1028. nBufferLength - Supplies the length in characters of the buffer that
  1029. is to receive the fully qualified path.
  1030. lpBuffer - Returns the fully qualified pathname corresponding to the
  1031. file that was found.
  1032. lpFilePart - Returns the address of the last component of the fully
  1033. qualified pathname.
  1034. Return Value:
  1035. The return value is the length of the string copied to lpBuffer, not
  1036. including the terminating null character. If the return value is
  1037. greater than nBufferLength, the return value is the size of the buffer
  1038. required to hold the pathname. The return value is zero if the
  1039. function failed.
  1040. --*/
  1041. {
  1042. UNICODE_STRING Path;
  1043. UNICODE_STRING FileName;
  1044. UNICODE_STRING DefaultExtension;
  1045. UNICODE_STRING CallersBuffer;
  1046. LPWSTR AllocatedPath = NULL;
  1047. RTL_PATH_TYPE PathType;
  1048. SIZE_T BytesRequired = 0;
  1049. SIZE_T FilePartPrefixCch = 0;
  1050. NTSTATUS Status;
  1051. DWORD dwReturnValue = 0;
  1052. //
  1053. // The guts of this function are now in common ntdll code; however the win32 search
  1054. // path has a few interesting differences from the ntdll search path code. First, it
  1055. // does not search the path if the filename is ".\foo" or "..\foo" and second, when the
  1056. // filename passed in is not a relative path but the file is not found, the default
  1057. // extension is applied regardless of whether the existing filename has an extension.
  1058. //
  1059. // These flags enable those feature-compatibility modes.
  1060. //
  1061. ULONG SearchPathFlags =
  1062. RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH |
  1063. RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION;
  1064. if (lpFilePart != NULL)
  1065. *lpFilePart = NULL;
  1066. Path.Buffer = NULL;
  1067. RtlInitUnicodeString(&FileName, lpFileName);
  1068. //
  1069. // trim trailing spaces, and then check for a real filelength
  1070. // if length is 0 (NULL, "", or " ") passed in then abort the
  1071. // search
  1072. //
  1073. while ((FileName.Length >= sizeof(WCHAR)) &&
  1074. (FileName.Buffer[(FileName.Length / sizeof(WCHAR)) - 1] == L' '))
  1075. FileName.Length -= sizeof(WCHAR);
  1076. if (FileName.Length == 0) {
  1077. SetLastError(ERROR_INVALID_PARAMETER);
  1078. goto Exit;
  1079. }
  1080. RtlInitUnicodeString(&DefaultExtension, lpExtension);
  1081. if ( !ARGUMENT_PRESENT(lpPath) ) {
  1082. SIZE_T Cch;
  1083. Path.Buffer = BaseComputeProcessSearchPath();
  1084. if (Path.Buffer == NULL) {
  1085. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1086. goto Exit;
  1087. }
  1088. Cch = lstrlenW(Path.Buffer);
  1089. if (Cch > UNICODE_STRING_MAX_CHARS) {
  1090. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1091. goto Exit;
  1092. }
  1093. Path.Length = (USHORT) (Cch * sizeof(WCHAR));
  1094. Path.MaximumLength = Path.Length;
  1095. SearchPathFlags |= RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION;
  1096. } else {
  1097. Status = RtlInitUnicodeStringEx(&Path, lpPath);
  1098. if (NT_ERROR(Status)) {
  1099. BaseSetLastNTError(Status);
  1100. goto Exit;
  1101. }
  1102. }
  1103. CallersBuffer.Length = 0;
  1104. if (nBufferLength > UNICODE_STRING_MAX_CHARS) {
  1105. CallersBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
  1106. } else {
  1107. CallersBuffer.MaximumLength = (USHORT) (nBufferLength * sizeof(WCHAR));
  1108. }
  1109. CallersBuffer.Buffer = lpBuffer;
  1110. Status = RtlDosSearchPath_Ustr(
  1111. SearchPathFlags,
  1112. &Path,
  1113. &FileName,
  1114. &DefaultExtension,
  1115. &CallersBuffer,
  1116. NULL, // dynamicstring
  1117. NULL, // fullfilenameout
  1118. &FilePartPrefixCch,
  1119. &BytesRequired);
  1120. if (NT_ERROR(Status)) {
  1121. #if DBG
  1122. // Don't bother with debug spew for the two common expected cases.
  1123. if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL)) {
  1124. DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n", __FUNCTION__, &FileName, Status);
  1125. DbgPrint(" Path = %wZ\n", &Path);
  1126. }
  1127. #endif // DBG
  1128. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1129. SIZE_T CchRequired = BytesRequired / sizeof(WCHAR);
  1130. if (CchRequired > 0xffffffff) {
  1131. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1132. goto Exit;
  1133. }
  1134. dwReturnValue = (DWORD) CchRequired;
  1135. goto Exit;
  1136. }
  1137. // Only set the last error if it wasn't an insufficient buffer; this is just preserving
  1138. // Windows 2000 behavior.
  1139. BaseSetLastNTError(Status);
  1140. goto Exit;
  1141. }
  1142. #ifdef WX86
  1143. if (UseKnownWx86Dll) {
  1144. WCHAR TempBuffer[MAX_PATH];
  1145. RtlCopyMemory(TempBuffer, lpBuffer, CallersBuffer.Length);
  1146. TempBuffer[CallersBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
  1147. dwReturnValue = GetFullPathNameWithWx86Override(
  1148. TempBuffer,
  1149. nBufferLength,
  1150. lpBuffer,
  1151. lpFilePart
  1152. );
  1153. goto Exit;
  1154. } else if (lpFilePart != NULL) {
  1155. *lpFilePart = lpBuffer + FilePartPrefixCch;
  1156. }
  1157. #else
  1158. if (lpFilePart != NULL) {
  1159. *lpFilePart = lpBuffer + FilePartPrefixCch;
  1160. }
  1161. #endif // WX86
  1162. dwReturnValue = CallersBuffer.Length / sizeof(WCHAR);
  1163. Exit:
  1164. if ((Path.Buffer != lpPath) && (Path.Buffer != NULL))
  1165. RtlFreeHeap(RtlProcessHeap(), 0, Path.Buffer);
  1166. return dwReturnValue;
  1167. }
  1168. DWORD
  1169. APIENTRY
  1170. GetTempPathA(
  1171. DWORD nBufferLength,
  1172. LPSTR lpBuffer
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. ANSI thunk to GetTempPathW
  1177. --*/
  1178. {
  1179. ANSI_STRING AnsiString;
  1180. UNICODE_STRING UnicodeString;
  1181. NTSTATUS Status;
  1182. ULONG cbAnsiString;
  1183. UnicodeString.MaximumLength = (USHORT)((nBufferLength<<1)+sizeof(UNICODE_NULL));
  1184. UnicodeString.Buffer = RtlAllocateHeap(
  1185. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  1186. UnicodeString.MaximumLength
  1187. );
  1188. if ( !UnicodeString.Buffer ) {
  1189. BaseSetLastNTError(STATUS_NO_MEMORY);
  1190. return 0;
  1191. }
  1192. UnicodeString.Length = (USHORT)GetTempPathW(
  1193. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
  1194. UnicodeString.Buffer
  1195. )*2;
  1196. if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
  1197. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  1198. //
  1199. // given buffer size is too small.
  1200. // allocate enough size of buffer and try again
  1201. //
  1202. // we need to get entire unicode temporary path
  1203. // otherwise we can't figure out the exact length
  1204. // of corresponding ansi string (cbAnsiString).
  1205. UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
  1206. MAKE_TAG( TMP_TAG ),
  1207. UnicodeString.Length+ sizeof(UNICODE_NULL));
  1208. if ( !UnicodeString.Buffer ) {
  1209. BaseSetLastNTError(STATUS_NO_MEMORY);
  1210. return 0;
  1211. }
  1212. UnicodeString.Length = (USHORT)GetTempPathW(
  1213. (DWORD)(UnicodeString.Length)/2,
  1214. UnicodeString.Buffer) * 2;
  1215. Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
  1216. UnicodeString.Buffer,
  1217. UnicodeString.Length );
  1218. if ( !NT_SUCCESS(Status) ) {
  1219. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  1220. BaseSetLastNTError(Status);
  1221. return 0;
  1222. }
  1223. else if ( nBufferLength <= cbAnsiString ) {
  1224. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  1225. return cbAnsiString + sizeof(ANSI_NULL);
  1226. }
  1227. }
  1228. AnsiString.Buffer = lpBuffer;
  1229. AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
  1230. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  1231. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  1232. if ( !NT_SUCCESS(Status) ) {
  1233. BaseSetLastNTError(Status);
  1234. return 0;
  1235. }
  1236. return AnsiString.Length;
  1237. }
  1238. DWORD
  1239. APIENTRY
  1240. GetTempPathW(
  1241. DWORD nBufferLength,
  1242. LPWSTR lpBuffer
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. This function is used to return the pathname of the directory that
  1247. should be used to create temporary files.
  1248. Arguments:
  1249. nBufferLength - Supplies the length in bytes of the buffer that is
  1250. to receive the temporary file path.
  1251. lpBuffer - Returns the pathname of the directory that should be used
  1252. to create temporary files in.
  1253. Return Value:
  1254. The return value is the length of the string copied to lpBuffer, not
  1255. including the terminating null character. If the return value is
  1256. greater than nSize, the return value is the size of the buffer
  1257. required to hold the pathname. The return value is zero if the
  1258. function failed.
  1259. --*/
  1260. {
  1261. return BasepGetTempPathW(0, nBufferLength, lpBuffer);
  1262. }
  1263. DWORD
  1264. APIENTRY
  1265. BasepGetTempPathW(
  1266. ULONG Flags,
  1267. DWORD nBufferLength,
  1268. LPWSTR lpBuffer
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This function is used to return the pathname of the directory that
  1273. should be used to create temporary files.
  1274. Arguments:
  1275. nBufferLength - Supplies the length in bytes of the buffer that is
  1276. to receive the temporary file path.
  1277. lpBuffer - Returns the pathname of the directory that should be used
  1278. to create temporary files in.
  1279. Flags -
  1280. Return Value:
  1281. The return value is the length of the string copied to lpBuffer, not
  1282. including the terminating null character. If the return value is
  1283. greater than nSize, the return value is the size of the buffer
  1284. required to hold the pathname. The return value is zero if the
  1285. function failed.
  1286. --*/
  1287. {
  1288. DWORD Length;
  1289. BOOLEAN AddTrailingSlash;
  1290. UNICODE_STRING EnvironmentValue;
  1291. NTSTATUS Status;
  1292. LPWSTR Name;
  1293. ULONG Position;
  1294. if (
  1295. (Flags & ~BASEP_GET_TEMP_PATH_PRESERVE_TEB) != 0
  1296. ) {
  1297. BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
  1298. return 0;
  1299. }
  1300. //
  1301. // Some apps don't work with the new long path for the temp directory
  1302. //
  1303. if (APPCOMPATFLAG(KACF_GETTEMPPATH)) {
  1304. #define OLD_TEMP_PATH L"c:\\temp\\"
  1305. #define OLD_TEMP_PATH_SIZE (sizeof(OLD_TEMP_PATH) / sizeof(WCHAR))
  1306. BOOL bRet;
  1307. //
  1308. // If there isn't enough space provided in the buffer return
  1309. // the desired size.
  1310. //
  1311. if (nBufferLength < OLD_TEMP_PATH_SIZE) {
  1312. return OLD_TEMP_PATH_SIZE;
  1313. }
  1314. wcscpy(lpBuffer, OLD_TEMP_PATH);
  1315. //
  1316. // Use the correct drive letter
  1317. //
  1318. lpBuffer[0] = BaseWindowsDirectory.Buffer[0];
  1319. bRet = CreateDirectoryW(lpBuffer, NULL);
  1320. if (!bRet) {
  1321. if (GetLastError() != ERROR_ALREADY_EXISTS)
  1322. return 0;
  1323. }
  1324. return OLD_TEMP_PATH_SIZE - 1;
  1325. }
  1326. nBufferLength *= 2;
  1327. EnvironmentValue = NtCurrentTeb()->StaticUnicodeString;
  1328. if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
  1329. EnvironmentValue.Buffer = (PWSTR)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), EnvironmentValue.MaximumLength);
  1330. if (EnvironmentValue.Buffer == NULL) {
  1331. BaseSetLastNTError(STATUS_NO_MEMORY);
  1332. return 0;
  1333. }
  1334. }
  1335. __try {
  1336. AddTrailingSlash = FALSE;
  1337. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTmpVariableName,&EnvironmentValue);
  1338. if ( !NT_SUCCESS(Status) ) {
  1339. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTempVariableName,&EnvironmentValue);
  1340. if ( !NT_SUCCESS(Status) ) {
  1341. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseUserProfileVariableName,&EnvironmentValue);
  1342. }
  1343. }
  1344. if ( NT_SUCCESS(Status) ) {
  1345. Name = EnvironmentValue.Buffer;
  1346. if ( Name[(EnvironmentValue.Length>>1)-1] != (WCHAR)'\\' ) {
  1347. AddTrailingSlash = TRUE;
  1348. }
  1349. }
  1350. else {
  1351. Name = BaseWindowsDirectory.Buffer;
  1352. if ( Name[(BaseWindowsDirectory.Length>>1)-1] != (WCHAR)'\\' ) {
  1353. AddTrailingSlash = TRUE;
  1354. }
  1355. }
  1356. Length = RtlGetFullPathName_U(
  1357. Name,
  1358. nBufferLength,
  1359. lpBuffer,
  1360. NULL
  1361. );
  1362. Position = Length>>1;
  1363. //
  1364. // Make sure there is room for a trailing back slash
  1365. //
  1366. if ( Length && Length < nBufferLength ) {
  1367. if ( lpBuffer[Position-1] != '\\' ) {
  1368. if ( Length+sizeof((WCHAR)'\\') < nBufferLength ) {
  1369. lpBuffer[Position] = (WCHAR)'\\';
  1370. lpBuffer[Position+1] = UNICODE_NULL;
  1371. return (Length+sizeof((WCHAR)'\\'))/2;
  1372. }
  1373. else {
  1374. return (Length+sizeof((WCHAR)'\\')+sizeof(UNICODE_NULL))/2;
  1375. }
  1376. }
  1377. else {
  1378. return Length/2;
  1379. }
  1380. }
  1381. else {
  1382. if ( AddTrailingSlash ) {
  1383. Length += sizeof((WCHAR)'\\');
  1384. }
  1385. return Length/2;
  1386. }
  1387. }
  1388. __finally {
  1389. if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
  1390. RtlFreeHeap(RtlProcessHeap(), 0, EnvironmentValue.Buffer);
  1391. }
  1392. }
  1393. }
  1394. UINT
  1395. APIENTRY
  1396. GetTempFileNameA(
  1397. LPCSTR lpPathName,
  1398. LPCSTR lpPrefixString,
  1399. UINT uUnique,
  1400. LPSTR lpTempFileName
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. ANSI thunk to GetTempFileNameW
  1405. --*/
  1406. {
  1407. PUNICODE_STRING Unicode;
  1408. UNICODE_STRING UnicodePrefix;
  1409. NTSTATUS Status;
  1410. UINT ReturnValue;
  1411. UNICODE_STRING UnicodeResult;
  1412. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
  1413. if (Unicode == NULL) {
  1414. return 0;
  1415. }
  1416. if (!Basep8BitStringToDynamicUnicodeString( &UnicodePrefix, lpPrefixString )) {
  1417. return 0;
  1418. }
  1419. UnicodeResult.MaximumLength = (USHORT)((MAX_PATH<<1)+sizeof(UNICODE_NULL));
  1420. UnicodeResult.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeResult.MaximumLength);
  1421. if ( !UnicodeResult.Buffer ) {
  1422. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1423. RtlFreeUnicodeString(&UnicodePrefix);
  1424. return 0;
  1425. }
  1426. ReturnValue = GetTempFileNameW(
  1427. Unicode->Buffer,
  1428. UnicodePrefix.Buffer,
  1429. uUnique,
  1430. UnicodeResult.Buffer
  1431. );
  1432. if ( ReturnValue ) {
  1433. ANSI_STRING AnsiString;
  1434. RtlInitUnicodeString(&UnicodeResult,UnicodeResult.Buffer);
  1435. AnsiString.Buffer = lpTempFileName;
  1436. AnsiString.MaximumLength = MAX_PATH+1;
  1437. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeResult,FALSE);
  1438. if ( !NT_SUCCESS(Status) ) {
  1439. BaseSetLastNTError(Status);
  1440. ReturnValue = 0;
  1441. }
  1442. }
  1443. RtlFreeUnicodeString(&UnicodePrefix);
  1444. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeResult.Buffer);
  1445. return ReturnValue;
  1446. }
  1447. UINT
  1448. APIENTRY
  1449. GetTempFileNameW(
  1450. LPCWSTR lpPathName,
  1451. LPCWSTR lpPrefixString,
  1452. UINT uUnique,
  1453. LPWSTR lpTempFileName
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. This function creates a temporary filename of the following form:
  1458. drive:\path\prefixuuuu.tmp
  1459. In this syntax line, drive:\path\ is the path specified by the
  1460. lpPathName parameter; prefix is all the letters (up to the first
  1461. three) of the string pointed to by the lpPrefixString parameter; and
  1462. uuuu is the hexadecimal value of the number specified by the
  1463. uUnique parameter.
  1464. To avoid problems resulting from converting OEM character an string
  1465. to an ANSI string, an application should call the CreateFile
  1466. function to create the temporary file.
  1467. If the uUnique parameter is zero, GetTempFileName attempts to form a
  1468. unique number based on the current system time. If a file with the
  1469. resulting filename exists, the number is increased by one and the
  1470. test for existence is repeated. This continues until a unique
  1471. filename is found; GetTempFileName then creates a file by that name
  1472. and closes it. No attempt is made to create and open the file when
  1473. uUnique is nonzero.
  1474. Arguments:
  1475. lpPathName - Specifies the null terminated pathname of the directory
  1476. to create the temporary file within.
  1477. lpPrefixString - Points to a null-terminated character string to be
  1478. used as the temporary filename prefix. This string must consist
  1479. of characters in the OEM-defined character set.
  1480. uUnique - Specifies an unsigned integer.
  1481. lpTempFileName - Points to the buffer that is to receive the
  1482. temporary filename. This string consists of characters in the
  1483. OEM-defined character set. This buffer should be at least MAX_PATH
  1484. characters in length to allow sufficient room for the pathname.
  1485. Return Value:
  1486. The return value specifies a unique numeric value used in the
  1487. temporary filename. If a nonzero value was given for the uUnique
  1488. parameter, the return value specifies this same number.
  1489. --*/
  1490. {
  1491. #if !defined(BUILD_WOW6432)
  1492. BASE_API_MSG m;
  1493. PBASE_GETTEMPFILE_MSG a = &m.u.GetTempFile;
  1494. #endif
  1495. LPWSTR p,savedp;
  1496. ULONG Length;
  1497. HANDLE FileHandle;
  1498. ULONG PassCount;
  1499. DWORD LastError;
  1500. UNICODE_STRING UnicodePath, UnicodePrefix;
  1501. CHAR UniqueAsAnsi[8];
  1502. CHAR *c;
  1503. ULONG i;
  1504. #if defined(BUILD_WOW6432)
  1505. UINT uNewUnique;
  1506. #endif
  1507. PassCount = 0;
  1508. RtlInitUnicodeString(&UnicodePath,lpPathName);
  1509. Length = UnicodePath.Length;
  1510. RtlMoveMemory(lpTempFileName,lpPathName,UnicodePath.MaximumLength);
  1511. if ( !Length || lpTempFileName[(Length>>1)-1] != (WCHAR)'\\' ) {
  1512. lpTempFileName[Length>>1] = (WCHAR)'\\';
  1513. Length += sizeof(UNICODE_NULL);
  1514. }
  1515. lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
  1516. i = GetFileAttributesW(lpTempFileName);
  1517. if (i == 0xFFFFFFFF) {
  1518. lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
  1519. lpTempFileName[(Length>>1)] = UNICODE_NULL;
  1520. i = GetFileAttributesW(lpTempFileName);
  1521. lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
  1522. }
  1523. if ( (i == 0xFFFFFFFF) ||
  1524. !(i & FILE_ATTRIBUTE_DIRECTORY) ) {
  1525. SetLastError(ERROR_DIRECTORY);
  1526. return FALSE;
  1527. }
  1528. lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
  1529. RtlInitUnicodeString(&UnicodePrefix,lpPrefixString);
  1530. if ( UnicodePrefix.Length > (USHORT)6 ) {
  1531. UnicodePrefix.Length = (USHORT)6;
  1532. }
  1533. p = &lpTempFileName[Length>>1];
  1534. Length = UnicodePrefix.Length;
  1535. RtlMoveMemory(p,lpPrefixString,Length);
  1536. p += (Length>>1);
  1537. savedp = p;
  1538. //
  1539. // If uUnique is not specified, then get one
  1540. //
  1541. uUnique = uUnique & 0x0000ffff;
  1542. try_again:
  1543. p = savedp;
  1544. if ( !uUnique ) {
  1545. #if defined(BUILD_WOW6432)
  1546. uNewUnique = CsrBasepGetTempFile();
  1547. if ( uNewUnique == 0 ) {
  1548. #else
  1549. CsrClientCallServer( (PCSR_API_MSG)&m,
  1550. NULL,
  1551. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1552. BasepGetTempFile
  1553. ),
  1554. sizeof( *a )
  1555. );
  1556. a->uUnique = (UINT)m.ReturnValue;
  1557. if ( m.ReturnValue == 0 ) {
  1558. #endif
  1559. PassCount++;
  1560. if ( PassCount & 0xffff0000 ) {
  1561. return 0;
  1562. }
  1563. goto try_again;
  1564. }
  1565. }
  1566. else {
  1567. #if defined(BUILD_WOW6432)
  1568. uNewUnique = uUnique;
  1569. #else
  1570. a->uUnique = uUnique;
  1571. #endif
  1572. }
  1573. //
  1574. // Convert the unique value to a 4 byte character string
  1575. //
  1576. #if defined(BUILD_WOW6432)
  1577. RtlIntegerToChar ((ULONG) uNewUnique,16,5,UniqueAsAnsi);
  1578. #else
  1579. RtlIntegerToChar ((ULONG) a->uUnique,16,5,UniqueAsAnsi);
  1580. #endif
  1581. c = UniqueAsAnsi;
  1582. for(i=0;i<4;i++){
  1583. *p = RtlAnsiCharToUnicodeChar(&c);
  1584. if ( *p == UNICODE_NULL ) {
  1585. break;
  1586. }
  1587. p++;
  1588. }
  1589. RtlMoveMemory(p,BaseDotTmpSuffixName.Buffer,BaseDotTmpSuffixName.MaximumLength);
  1590. if ( !uUnique ) {
  1591. //
  1592. // test for resulting name being a device (prefix com, uUnique 1-9...
  1593. //
  1594. if ( RtlIsDosDeviceName_U(lpTempFileName) ) {
  1595. PassCount++;
  1596. if ( PassCount & 0xffff0000 ) {
  1597. SetLastError(ERROR_INVALID_NAME);
  1598. return 0;
  1599. }
  1600. goto try_again;
  1601. }
  1602. FileHandle = CreateFileW(
  1603. lpTempFileName,
  1604. GENERIC_READ,
  1605. 0,
  1606. NULL,
  1607. CREATE_NEW,
  1608. FILE_ATTRIBUTE_NORMAL,
  1609. NULL
  1610. );
  1611. //
  1612. // If the create worked, then we are ok. Just close the file.
  1613. // Otherwise, try again.
  1614. //
  1615. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  1616. NtClose(FileHandle);
  1617. }
  1618. else {
  1619. //
  1620. // FIXFIX This test should be inverted when time permits
  1621. // sufficient testing to nail down the error codes that
  1622. // would indicate is is reasonable to continue the loop
  1623. // as opposed to stop the loop. All it currently takes is
  1624. // CreateFile coming back with an error we don't know about
  1625. // to make us spin here for a long time.
  1626. //
  1627. LastError = GetLastError();
  1628. switch (LastError) {
  1629. case ERROR_INVALID_PARAMETER :
  1630. case ERROR_WRITE_PROTECT :
  1631. case ERROR_FILE_NOT_FOUND :
  1632. case ERROR_BAD_PATHNAME :
  1633. case ERROR_INVALID_NAME :
  1634. case ERROR_PATH_NOT_FOUND :
  1635. case ERROR_NETWORK_ACCESS_DENIED :
  1636. case ERROR_DISK_CORRUPT :
  1637. case ERROR_FILE_CORRUPT :
  1638. case ERROR_DISK_FULL :
  1639. return 0;
  1640. case ERROR_ACCESS_DENIED :
  1641. // It's possible for us to hit this if there's a
  1642. // directory with the name we're trying; in that
  1643. // case, we can usefully continue.
  1644. // CreateFile() uses BaseSetLastNTError() to set
  1645. // LastStatusValue to the actual NT error in the
  1646. // TEB; we just need to check it, and only abort
  1647. // if it's not a directory.
  1648. // This was bug #397477.
  1649. if (NtCurrentTeb()->LastStatusValue
  1650. != STATUS_FILE_IS_A_DIRECTORY)
  1651. return 0;
  1652. }
  1653. PassCount++;
  1654. if ( PassCount & 0xffff0000 ) {
  1655. return 0;
  1656. }
  1657. goto try_again;
  1658. }
  1659. }
  1660. #if defined(BUILD_WOW6432)
  1661. return uNewUnique;
  1662. #else
  1663. return a->uUnique;
  1664. #endif
  1665. }
  1666. BOOL
  1667. APIENTRY
  1668. GetDiskFreeSpaceA(
  1669. LPCSTR lpRootPathName,
  1670. LPDWORD lpSectorsPerCluster,
  1671. LPDWORD lpBytesPerSector,
  1672. LPDWORD lpNumberOfFreeClusters,
  1673. LPDWORD lpTotalNumberOfClusters
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. ANSI thunk to GetDiskFreeSpaceW
  1678. --*/
  1679. {
  1680. PUNICODE_STRING Unicode;
  1681. if (!ARGUMENT_PRESENT( lpRootPathName )) {
  1682. lpRootPathName = "\\";
  1683. }
  1684. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  1685. if (Unicode == NULL) {
  1686. return FALSE;
  1687. }
  1688. return ( GetDiskFreeSpaceW(
  1689. (LPCWSTR)Unicode->Buffer,
  1690. lpSectorsPerCluster,
  1691. lpBytesPerSector,
  1692. lpNumberOfFreeClusters,
  1693. lpTotalNumberOfClusters
  1694. )
  1695. );
  1696. }
  1697. BOOL
  1698. APIENTRY
  1699. GetDiskFreeSpaceW(
  1700. LPCWSTR lpRootPathName,
  1701. LPDWORD lpSectorsPerCluster,
  1702. LPDWORD lpBytesPerSector,
  1703. LPDWORD lpNumberOfFreeClusters,
  1704. LPDWORD lpTotalNumberOfClusters
  1705. )
  1706. #define MAKE2GFRIENDLY(lpOut, dwSize) \
  1707. \
  1708. if (!bAppHack) { \
  1709. *lpOut = dwSize; \
  1710. } else { \
  1711. dwTemp = SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector; \
  1712. \
  1713. if (0x7FFFFFFF / dwTemp < dwSize) { \
  1714. \
  1715. *lpOut = 0x7FFFFFFF / dwTemp; \
  1716. } else { \
  1717. *lpOut = dwSize; \
  1718. } \
  1719. }
  1720. /*++
  1721. Routine Description:
  1722. The free space on a disk and the size parameters can be returned
  1723. using GetDiskFreeSpace.
  1724. Arguments:
  1725. lpRootPathName - An optional parameter, that if specified, supplies
  1726. the root directory of the disk whose free space is to be
  1727. returned for. If this parameter is not specified, then the root
  1728. of the current directory is used.
  1729. lpSectorsPerCluster - Returns the number of sectors per cluster
  1730. where a cluster is the allocation granularity on the disk.
  1731. lpBytesPerSector - Returns the number of bytes per sector.
  1732. lpNumberOfFreeClusters - Returns the total number of free clusters
  1733. on the disk.
  1734. lpTotalNumberOfClusters - Returns the total number of clusters on
  1735. the disk.
  1736. Return Value:
  1737. TRUE - The operation was successful.
  1738. FALSE/NULL - The operation failed. Extended error status is available
  1739. using GetLastError.
  1740. --*/
  1741. {
  1742. NTSTATUS Status;
  1743. OBJECT_ATTRIBUTES Obja;
  1744. HANDLE Handle;
  1745. UNICODE_STRING FileName;
  1746. IO_STATUS_BLOCK IoStatusBlock;
  1747. BOOLEAN TranslationStatus;
  1748. PVOID FreeBuffer;
  1749. FILE_FS_SIZE_INFORMATION SizeInfo;
  1750. WCHAR DefaultPath[2];
  1751. DWORD dwTemp;
  1752. BOOL bAppHack;
  1753. DefaultPath[0] = (WCHAR)'\\';
  1754. DefaultPath[1] = UNICODE_NULL;
  1755. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1756. ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
  1757. &FileName,
  1758. NULL,
  1759. NULL
  1760. );
  1761. if ( !TranslationStatus ) {
  1762. SetLastError(ERROR_PATH_NOT_FOUND);
  1763. return FALSE;
  1764. }
  1765. FreeBuffer = FileName.Buffer;
  1766. InitializeObjectAttributes(
  1767. &Obja,
  1768. &FileName,
  1769. OBJ_CASE_INSENSITIVE,
  1770. NULL,
  1771. NULL
  1772. );
  1773. //
  1774. // Open the file
  1775. //
  1776. Status = NtOpenFile(
  1777. &Handle,
  1778. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1779. &Obja,
  1780. &IoStatusBlock,
  1781. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1782. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
  1783. );
  1784. if ( !NT_SUCCESS(Status) ) {
  1785. BaseSetLastNTError(Status);
  1786. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1787. //
  1788. // Prior releases of NT where these parameters were not optional
  1789. // zeroed out this field even in the failure case. Some applications
  1790. // failed to check the return value from this function and instead
  1791. // relied on this side effect. I'm putting that back now so the apps
  1792. // can still treat an unformatted volume as a zero size volume.
  1793. //
  1794. if (ARGUMENT_PRESENT( lpBytesPerSector )) {
  1795. *lpBytesPerSector = 0;
  1796. }
  1797. return FALSE;
  1798. }
  1799. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1800. //
  1801. // Determine the size parameters of the volume.
  1802. //
  1803. Status = NtQueryVolumeInformationFile(
  1804. Handle,
  1805. &IoStatusBlock,
  1806. &SizeInfo,
  1807. sizeof(SizeInfo),
  1808. FileFsSizeInformation
  1809. );
  1810. NtClose(Handle);
  1811. if ( !NT_SUCCESS(Status) ) {
  1812. BaseSetLastNTError(Status);
  1813. return FALSE;
  1814. }
  1815. //
  1816. // See if the calling process needs hack to work with HDD > 2GB
  1817. // 2GB is 0x80000000 bytes and some apps treat that as a signed LONG.
  1818. //
  1819. if (APPCOMPATFLAG(KACF_GETDISKFREESPACE)) {
  1820. bAppHack = TRUE;
  1821. } else {
  1822. bAppHack = FALSE;
  1823. }
  1824. //
  1825. // Deal with 64 bit sizes
  1826. //
  1827. if ( SizeInfo.TotalAllocationUnits.HighPart ) {
  1828. SizeInfo.TotalAllocationUnits.LowPart = (ULONG)-1;
  1829. }
  1830. if ( SizeInfo.AvailableAllocationUnits.HighPart ) {
  1831. SizeInfo.AvailableAllocationUnits.LowPart = (ULONG)-1;
  1832. }
  1833. if (ARGUMENT_PRESENT( lpSectorsPerCluster )) {
  1834. *lpSectorsPerCluster = SizeInfo.SectorsPerAllocationUnit;
  1835. }
  1836. if (ARGUMENT_PRESENT( lpBytesPerSector )) {
  1837. *lpBytesPerSector = SizeInfo.BytesPerSector;
  1838. }
  1839. if (ARGUMENT_PRESENT( lpNumberOfFreeClusters )) {
  1840. MAKE2GFRIENDLY(lpNumberOfFreeClusters, SizeInfo.AvailableAllocationUnits.LowPart);
  1841. }
  1842. if (ARGUMENT_PRESENT( lpTotalNumberOfClusters )) {
  1843. MAKE2GFRIENDLY(lpTotalNumberOfClusters, SizeInfo.TotalAllocationUnits.LowPart);
  1844. }
  1845. return TRUE;
  1846. }
  1847. WINBASEAPI
  1848. BOOL
  1849. WINAPI
  1850. GetDiskFreeSpaceExA(
  1851. LPCSTR lpDirectoryName,
  1852. PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  1853. PULARGE_INTEGER lpTotalNumberOfBytes,
  1854. PULARGE_INTEGER lpTotalNumberOfFreeBytes
  1855. )
  1856. {
  1857. PUNICODE_STRING Unicode;
  1858. if (!ARGUMENT_PRESENT( lpDirectoryName )) {
  1859. lpDirectoryName = "\\";
  1860. }
  1861. Unicode = Basep8BitStringToStaticUnicodeString( lpDirectoryName );
  1862. if (Unicode == NULL) {
  1863. return FALSE;
  1864. }
  1865. return ( GetDiskFreeSpaceExW(
  1866. (LPCWSTR)Unicode->Buffer,
  1867. lpFreeBytesAvailableToCaller,
  1868. lpTotalNumberOfBytes,
  1869. lpTotalNumberOfFreeBytes
  1870. )
  1871. );
  1872. }
  1873. WINBASEAPI
  1874. BOOL
  1875. WINAPI
  1876. GetDiskFreeSpaceExW(
  1877. LPCWSTR lpDirectoryName,
  1878. PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  1879. PULARGE_INTEGER lpTotalNumberOfBytes,
  1880. PULARGE_INTEGER lpTotalNumberOfFreeBytes
  1881. )
  1882. {
  1883. NTSTATUS Status;
  1884. OBJECT_ATTRIBUTES Obja;
  1885. HANDLE Handle;
  1886. UNICODE_STRING FileName;
  1887. IO_STATUS_BLOCK IoStatusBlock;
  1888. BOOLEAN TranslationStatus;
  1889. PVOID FreeBuffer;
  1890. union {
  1891. FILE_FS_SIZE_INFORMATION Normal;
  1892. FILE_FS_FULL_SIZE_INFORMATION Full;
  1893. } SizeInfo;
  1894. WCHAR DefaultPath[2];
  1895. ULARGE_INTEGER BytesPerAllocationUnit;
  1896. ULARGE_INTEGER FreeBytesAvailableToCaller;
  1897. ULARGE_INTEGER TotalNumberOfBytes;
  1898. DefaultPath[0] = (WCHAR)'\\';
  1899. DefaultPath[1] = UNICODE_NULL;
  1900. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1901. ARGUMENT_PRESENT(lpDirectoryName) ? lpDirectoryName : DefaultPath,
  1902. &FileName,
  1903. NULL,
  1904. NULL
  1905. );
  1906. if ( !TranslationStatus ) {
  1907. SetLastError(ERROR_PATH_NOT_FOUND);
  1908. return FALSE;
  1909. }
  1910. FreeBuffer = FileName.Buffer;
  1911. InitializeObjectAttributes(
  1912. &Obja,
  1913. &FileName,
  1914. OBJ_CASE_INSENSITIVE,
  1915. NULL,
  1916. NULL
  1917. );
  1918. //
  1919. // Open the file
  1920. //
  1921. Status = NtOpenFile(
  1922. &Handle,
  1923. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1924. &Obja,
  1925. &IoStatusBlock,
  1926. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1927. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
  1928. );
  1929. if ( !NT_SUCCESS(Status) ) {
  1930. BaseSetLastNTError(Status);
  1931. if ( GetLastError() == ERROR_FILE_NOT_FOUND ) {
  1932. SetLastError(ERROR_PATH_NOT_FOUND);
  1933. }
  1934. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1935. return FALSE;
  1936. }
  1937. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1938. //
  1939. // If the caller wants the volume total then try to get a full
  1940. // file size.
  1941. //
  1942. if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
  1943. Status = NtQueryVolumeInformationFile(
  1944. Handle,
  1945. &IoStatusBlock,
  1946. &SizeInfo,
  1947. sizeof(SizeInfo.Full),
  1948. FileFsFullSizeInformation
  1949. );
  1950. if ( NT_SUCCESS(Status) ) {
  1951. NtClose(Handle);
  1952. BytesPerAllocationUnit.QuadPart =
  1953. SizeInfo.Full.BytesPerSector * SizeInfo.Full.SectorsPerAllocationUnit;
  1954. if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
  1955. lpFreeBytesAvailableToCaller->QuadPart =
  1956. BytesPerAllocationUnit.QuadPart *
  1957. SizeInfo.Full.CallerAvailableAllocationUnits.QuadPart;
  1958. }
  1959. if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
  1960. lpTotalNumberOfBytes->QuadPart =
  1961. BytesPerAllocationUnit.QuadPart * SizeInfo.Full.TotalAllocationUnits.QuadPart;
  1962. }
  1963. lpTotalNumberOfFreeBytes->QuadPart =
  1964. BytesPerAllocationUnit.QuadPart *
  1965. SizeInfo.Full.ActualAvailableAllocationUnits.QuadPart;
  1966. return TRUE;
  1967. }
  1968. }
  1969. //
  1970. // Determine the size parameters of the volume.
  1971. //
  1972. Status = NtQueryVolumeInformationFile(
  1973. Handle,
  1974. &IoStatusBlock,
  1975. &SizeInfo,
  1976. sizeof(SizeInfo.Normal),
  1977. FileFsSizeInformation
  1978. );
  1979. NtClose(Handle);
  1980. if ( !NT_SUCCESS(Status) ) {
  1981. BaseSetLastNTError(Status);
  1982. return FALSE;
  1983. }
  1984. BytesPerAllocationUnit.QuadPart =
  1985. SizeInfo.Normal.BytesPerSector * SizeInfo.Normal.SectorsPerAllocationUnit;
  1986. FreeBytesAvailableToCaller.QuadPart =
  1987. BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.AvailableAllocationUnits.QuadPart;
  1988. TotalNumberOfBytes.QuadPart =
  1989. BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.TotalAllocationUnits.QuadPart;
  1990. if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
  1991. lpFreeBytesAvailableToCaller->QuadPart = FreeBytesAvailableToCaller.QuadPart;
  1992. }
  1993. if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
  1994. lpTotalNumberOfBytes->QuadPart = TotalNumberOfBytes.QuadPart;
  1995. }
  1996. if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
  1997. lpTotalNumberOfFreeBytes->QuadPart = FreeBytesAvailableToCaller.QuadPart;
  1998. }
  1999. return TRUE;
  2000. }
  2001. BOOL
  2002. APIENTRY
  2003. GetVolumeInformationA(
  2004. LPCSTR lpRootPathName,
  2005. LPSTR lpVolumeNameBuffer,
  2006. DWORD nVolumeNameSize,
  2007. LPDWORD lpVolumeSerialNumber,
  2008. LPDWORD lpMaximumComponentLength,
  2009. LPDWORD lpFileSystemFlags,
  2010. LPSTR lpFileSystemNameBuffer,
  2011. DWORD nFileSystemNameSize
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. ANSI thunk to GetVolumeInformationW
  2016. --*/
  2017. {
  2018. PUNICODE_STRING Unicode;
  2019. NTSTATUS Status;
  2020. UNICODE_STRING UnicodeVolumeName;
  2021. UNICODE_STRING UnicodeFileSystemName;
  2022. ANSI_STRING AnsiVolumeName;
  2023. ANSI_STRING AnsiFileSystemName;
  2024. BOOL ReturnValue;
  2025. if (!ARGUMENT_PRESENT( lpRootPathName )) {
  2026. lpRootPathName = "\\";
  2027. }
  2028. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  2029. if (Unicode == NULL) {
  2030. return FALSE;
  2031. }
  2032. UnicodeVolumeName.Buffer = NULL;
  2033. UnicodeFileSystemName.Buffer = NULL;
  2034. UnicodeVolumeName.MaximumLength = 0;
  2035. UnicodeFileSystemName.MaximumLength = 0;
  2036. AnsiVolumeName.Buffer = lpVolumeNameBuffer;
  2037. AnsiVolumeName.MaximumLength = (USHORT)(nVolumeNameSize+1);
  2038. AnsiFileSystemName.Buffer = lpFileSystemNameBuffer;
  2039. AnsiFileSystemName.MaximumLength = (USHORT)(nFileSystemNameSize+1);
  2040. try {
  2041. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2042. UnicodeVolumeName.MaximumLength = AnsiVolumeName.MaximumLength << 1;
  2043. UnicodeVolumeName.Buffer = RtlAllocateHeap(
  2044. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2045. UnicodeVolumeName.MaximumLength
  2046. );
  2047. if ( !UnicodeVolumeName.Buffer ) {
  2048. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2049. return FALSE;
  2050. }
  2051. }
  2052. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2053. UnicodeFileSystemName.MaximumLength = AnsiFileSystemName.MaximumLength << 1;
  2054. UnicodeFileSystemName.Buffer = RtlAllocateHeap(
  2055. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2056. UnicodeFileSystemName.MaximumLength
  2057. );
  2058. if ( !UnicodeFileSystemName.Buffer ) {
  2059. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2060. return FALSE;
  2061. }
  2062. }
  2063. ReturnValue = GetVolumeInformationW(
  2064. (LPCWSTR)Unicode->Buffer,
  2065. UnicodeVolumeName.Buffer,
  2066. nVolumeNameSize,
  2067. lpVolumeSerialNumber,
  2068. lpMaximumComponentLength,
  2069. lpFileSystemFlags,
  2070. UnicodeFileSystemName.Buffer,
  2071. nFileSystemNameSize
  2072. );
  2073. if ( ReturnValue ) {
  2074. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2075. RtlInitUnicodeString(
  2076. &UnicodeVolumeName,
  2077. UnicodeVolumeName.Buffer
  2078. );
  2079. Status = BasepUnicodeStringTo8BitString(
  2080. &AnsiVolumeName,
  2081. &UnicodeVolumeName,
  2082. FALSE
  2083. );
  2084. if ( !NT_SUCCESS(Status) ) {
  2085. BaseSetLastNTError(Status);
  2086. return FALSE;
  2087. }
  2088. }
  2089. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2090. RtlInitUnicodeString(
  2091. &UnicodeFileSystemName,
  2092. UnicodeFileSystemName.Buffer
  2093. );
  2094. Status = BasepUnicodeStringTo8BitString(
  2095. &AnsiFileSystemName,
  2096. &UnicodeFileSystemName,
  2097. FALSE
  2098. );
  2099. if ( !NT_SUCCESS(Status) ) {
  2100. BaseSetLastNTError(Status);
  2101. return FALSE;
  2102. }
  2103. }
  2104. }
  2105. }
  2106. finally {
  2107. if ( UnicodeVolumeName.Buffer ) {
  2108. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeVolumeName.Buffer);
  2109. }
  2110. if ( UnicodeFileSystemName.Buffer ) {
  2111. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeFileSystemName.Buffer);
  2112. }
  2113. }
  2114. return ReturnValue;
  2115. }
  2116. BOOL
  2117. APIENTRY
  2118. GetVolumeInformationW(
  2119. LPCWSTR lpRootPathName,
  2120. LPWSTR lpVolumeNameBuffer,
  2121. DWORD nVolumeNameSize,
  2122. LPDWORD lpVolumeSerialNumber,
  2123. LPDWORD lpMaximumComponentLength,
  2124. LPDWORD lpFileSystemFlags,
  2125. LPWSTR lpFileSystemNameBuffer,
  2126. DWORD nFileSystemNameSize
  2127. )
  2128. /*++
  2129. Routine Description:
  2130. This function returns information about the file system whose root
  2131. directory is specified.
  2132. Arguments:
  2133. lpRootPathName - An optional parameter, that if specified, supplies
  2134. the root directory of the file system that information is to be
  2135. returned about. If this parameter is not specified, then the
  2136. root of the current directory is used.
  2137. lpVolumeNameBuffer - An optional parameter that if specified returns
  2138. the name of the specified volume.
  2139. nVolumeNameSize - Supplies the length of the volume name buffer.
  2140. This parameter is ignored if the volume name buffer is not
  2141. supplied.
  2142. lpVolumeSerialNumber - An optional parameter that if specified
  2143. points to a DWORD. The DWORD contains the 32-bit of the volume
  2144. serial number.
  2145. lpMaximumComponentLength - An optional parameter that if specified
  2146. returns the maximum length of a filename component supported by
  2147. the specified file system. A filename component is that portion
  2148. of a filename between pathname seperators.
  2149. lpFileSystemFlags - An optional parameter that if specified returns
  2150. flags associated with the specified file system.
  2151. lpFileSystemFlags Flags:
  2152. FS_CASE_IS_PRESERVED - Indicates that the case of file names
  2153. is preserved when the name is placed on disk.
  2154. FS_CASE_SENSITIVE - Indicates that the file system supports
  2155. case sensitive file name lookup.
  2156. FS_UNICODE_STORED_ON_DISK - Indicates that the file system
  2157. supports unicode in file names as they appear on disk.
  2158. lpFileSystemNameBuffer - An optional parameter that if specified returns
  2159. the name for the specified file system (e.g. FAT, HPFS...).
  2160. nFileSystemNameSize - Supplies the length of the file system name
  2161. buffer. This parameter is ignored if the file system name
  2162. buffer is not supplied.
  2163. Return Value:
  2164. TRUE - The operation was successful.
  2165. FALSE/NULL - The operation failed. Extended error status is available
  2166. using GetLastError.
  2167. --*/
  2168. {
  2169. NTSTATUS Status;
  2170. OBJECT_ATTRIBUTES Obja;
  2171. HANDLE Handle;
  2172. UNICODE_STRING FileName;
  2173. IO_STATUS_BLOCK IoStatusBlock;
  2174. BOOLEAN TranslationStatus;
  2175. PVOID FreeBuffer;
  2176. PFILE_FS_ATTRIBUTE_INFORMATION AttributeInfo;
  2177. PFILE_FS_VOLUME_INFORMATION VolumeInfo;
  2178. ULONG AttributeInfoLength;
  2179. ULONG VolumeInfoLength;
  2180. WCHAR DefaultPath[2];
  2181. BOOL rv;
  2182. ULONG HardErrorValue;
  2183. #if defined(BUILD_WOW6432)
  2184. ULONG HardErrorValue64;
  2185. #endif
  2186. PTEB Teb;
  2187. rv = FALSE;
  2188. DefaultPath[0] = (WCHAR)'\\';
  2189. DefaultPath[1] = UNICODE_NULL;
  2190. nVolumeNameSize *= 2;
  2191. nFileSystemNameSize *= 2;
  2192. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2193. ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
  2194. &FileName,
  2195. NULL,
  2196. NULL
  2197. );
  2198. if ( !TranslationStatus ) {
  2199. SetLastError(ERROR_PATH_NOT_FOUND);
  2200. return FALSE;
  2201. }
  2202. FreeBuffer = FileName.Buffer;
  2203. //
  2204. // Check to make sure a root was specified
  2205. //
  2206. if ( FileName.Buffer[(FileName.Length >> 1)-1] != '\\' ) {
  2207. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2208. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  2209. return FALSE;
  2210. }
  2211. InitializeObjectAttributes(
  2212. &Obja,
  2213. &FileName,
  2214. OBJ_CASE_INSENSITIVE,
  2215. NULL,
  2216. NULL
  2217. );
  2218. AttributeInfo = NULL;
  2219. VolumeInfo = NULL;
  2220. //
  2221. // Open the file
  2222. //
  2223. Teb = NtCurrentTeb();
  2224. HardErrorValue = Teb->HardErrorsAreDisabled;
  2225. Teb->HardErrorsAreDisabled = 1;
  2226. #if defined(BUILD_WOW6432)
  2227. HardErrorValue64 = NtCurrentTeb64()->HardErrorsAreDisabled;
  2228. NtCurrentTeb64()->HardErrorsAreDisabled = 1;
  2229. #endif
  2230. Status = NtOpenFile(
  2231. &Handle,
  2232. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  2233. &Obja,
  2234. &IoStatusBlock,
  2235. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2236. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  2237. );
  2238. Teb->HardErrorsAreDisabled = HardErrorValue;
  2239. #if defined(BUILD_WOW6432)
  2240. NtCurrentTeb64()->HardErrorsAreDisabled = HardErrorValue64;
  2241. #endif
  2242. if ( !NT_SUCCESS(Status) ) {
  2243. BaseSetLastNTError(Status);
  2244. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2245. return FALSE;
  2246. }
  2247. if ( !IsThisARootDirectory(Handle,&FileName) ) {
  2248. NtClose(Handle);
  2249. SetLastError(ERROR_DIR_NOT_ROOT);
  2250. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2251. return FALSE;
  2252. }
  2253. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2254. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ||
  2255. ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
  2256. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2257. VolumeInfoLength = sizeof(*VolumeInfo)+nVolumeNameSize;
  2258. }
  2259. else {
  2260. VolumeInfoLength = sizeof(*VolumeInfo)+MAX_PATH;
  2261. }
  2262. VolumeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), VolumeInfoLength);
  2263. if ( !VolumeInfo ) {
  2264. NtClose(Handle);
  2265. BaseSetLastNTError(STATUS_NO_MEMORY);
  2266. return FALSE;
  2267. }
  2268. }
  2269. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ||
  2270. ARGUMENT_PRESENT(lpMaximumComponentLength) ||
  2271. ARGUMENT_PRESENT(lpFileSystemFlags) ) {
  2272. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2273. AttributeInfoLength = sizeof(*AttributeInfo) + nFileSystemNameSize;
  2274. }
  2275. else {
  2276. AttributeInfoLength = sizeof(*AttributeInfo) + MAX_PATH;
  2277. }
  2278. AttributeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AttributeInfoLength);
  2279. if ( !AttributeInfo ) {
  2280. NtClose(Handle);
  2281. if ( VolumeInfo ) {
  2282. RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
  2283. }
  2284. BaseSetLastNTError(STATUS_NO_MEMORY);
  2285. return FALSE;
  2286. }
  2287. }
  2288. try {
  2289. if ( VolumeInfo ) {
  2290. Status = NtQueryVolumeInformationFile(
  2291. Handle,
  2292. &IoStatusBlock,
  2293. VolumeInfo,
  2294. VolumeInfoLength,
  2295. FileFsVolumeInformation
  2296. );
  2297. if ( !NT_SUCCESS(Status) ) {
  2298. BaseSetLastNTError(Status);
  2299. rv = FALSE;
  2300. goto finally_exit;
  2301. }
  2302. }
  2303. if ( AttributeInfo ) {
  2304. Status = NtQueryVolumeInformationFile(
  2305. Handle,
  2306. &IoStatusBlock,
  2307. AttributeInfo,
  2308. AttributeInfoLength,
  2309. FileFsAttributeInformation
  2310. );
  2311. if ( !NT_SUCCESS(Status) ) {
  2312. BaseSetLastNTError(Status);
  2313. rv = FALSE;
  2314. goto finally_exit;
  2315. }
  2316. }
  2317. try {
  2318. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2319. if ( VolumeInfo->VolumeLabelLength >= nVolumeNameSize ) {
  2320. SetLastError(ERROR_BAD_LENGTH);
  2321. rv = FALSE;
  2322. goto finally_exit;
  2323. }
  2324. else {
  2325. RtlMoveMemory( lpVolumeNameBuffer,
  2326. VolumeInfo->VolumeLabel,
  2327. VolumeInfo->VolumeLabelLength );
  2328. *(lpVolumeNameBuffer + (VolumeInfo->VolumeLabelLength >> 1)) = UNICODE_NULL;
  2329. }
  2330. }
  2331. if ( ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
  2332. *lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
  2333. }
  2334. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2335. if ( AttributeInfo->FileSystemNameLength >= nFileSystemNameSize ) {
  2336. SetLastError(ERROR_BAD_LENGTH);
  2337. rv = FALSE;
  2338. goto finally_exit;
  2339. }
  2340. else {
  2341. RtlMoveMemory( lpFileSystemNameBuffer,
  2342. AttributeInfo->FileSystemName,
  2343. AttributeInfo->FileSystemNameLength );
  2344. *(lpFileSystemNameBuffer + (AttributeInfo->FileSystemNameLength >> 1)) = UNICODE_NULL;
  2345. }
  2346. }
  2347. if ( ARGUMENT_PRESENT(lpMaximumComponentLength) ) {
  2348. *lpMaximumComponentLength = AttributeInfo->MaximumComponentNameLength;
  2349. }
  2350. if ( ARGUMENT_PRESENT(lpFileSystemFlags) ) {
  2351. *lpFileSystemFlags = AttributeInfo->FileSystemAttributes;
  2352. }
  2353. }
  2354. except (EXCEPTION_EXECUTE_HANDLER) {
  2355. BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
  2356. return FALSE;
  2357. }
  2358. rv = TRUE;
  2359. finally_exit:;
  2360. }
  2361. finally {
  2362. NtClose(Handle);
  2363. if ( VolumeInfo ) {
  2364. RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
  2365. }
  2366. if ( AttributeInfo ) {
  2367. RtlFreeHeap(RtlProcessHeap(), 0,AttributeInfo);
  2368. }
  2369. }
  2370. return rv;
  2371. }
  2372. DWORD
  2373. APIENTRY
  2374. GetLogicalDriveStringsA(
  2375. DWORD nBufferLength,
  2376. LPSTR lpBuffer
  2377. )
  2378. {
  2379. ULONG DriveMap;
  2380. ANSI_STRING RootName;
  2381. int i;
  2382. PUCHAR Dst;
  2383. DWORD BytesLeft;
  2384. DWORD BytesNeeded;
  2385. BOOL WeFailed;
  2386. CHAR szDrive[] = "A:\\";
  2387. BytesNeeded = 0;
  2388. BytesLeft = nBufferLength;
  2389. Dst = (PUCHAR)lpBuffer;
  2390. WeFailed = FALSE;
  2391. RtlInitAnsiString(&RootName, szDrive);
  2392. DriveMap = GetLogicalDrives();
  2393. for ( i=0; i<26; i++ ) {
  2394. RootName.Buffer[0] = (CHAR)((CHAR)i+'A');
  2395. if (DriveMap & (1 << i) ) {
  2396. BytesNeeded += RootName.MaximumLength;
  2397. if ( BytesNeeded < (USHORT)BytesLeft ) {
  2398. RtlMoveMemory(Dst,RootName.Buffer,RootName.MaximumLength);
  2399. Dst += RootName.MaximumLength;
  2400. *Dst = '\0';
  2401. }
  2402. else {
  2403. WeFailed = TRUE;
  2404. }
  2405. }
  2406. }
  2407. if ( WeFailed ) {
  2408. BytesNeeded++;
  2409. }
  2410. //
  2411. // Need to handle network uses;
  2412. //
  2413. return( BytesNeeded );
  2414. }
  2415. DWORD
  2416. APIENTRY
  2417. GetLogicalDriveStringsW(
  2418. DWORD nBufferLength,
  2419. LPWSTR lpBuffer
  2420. )
  2421. {
  2422. ULONG DriveMap;
  2423. UNICODE_STRING RootName;
  2424. int i;
  2425. PUCHAR Dst;
  2426. DWORD BytesLeft;
  2427. DWORD BytesNeeded;
  2428. BOOL WeFailed;
  2429. WCHAR wszDrive[] = L"A:\\";
  2430. nBufferLength = nBufferLength*2;
  2431. BytesNeeded = 0;
  2432. BytesLeft = nBufferLength;
  2433. Dst = (PUCHAR)lpBuffer;
  2434. WeFailed = FALSE;
  2435. RtlInitUnicodeString(&RootName, wszDrive);
  2436. DriveMap = GetLogicalDrives();
  2437. for ( i=0; i<26; i++ ) {
  2438. RootName.Buffer[0] = (WCHAR)((CHAR)i+'A');
  2439. if (DriveMap & (1 << i) ) {
  2440. BytesNeeded += RootName.MaximumLength;
  2441. if ( BytesNeeded < (USHORT)BytesLeft ) {
  2442. RtlMoveMemory(Dst,RootName.Buffer,RootName.MaximumLength);
  2443. Dst += RootName.MaximumLength;
  2444. *(PWSTR)Dst = UNICODE_NULL;
  2445. }
  2446. else {
  2447. WeFailed = TRUE;
  2448. }
  2449. }
  2450. }
  2451. if ( WeFailed ) {
  2452. BytesNeeded += 2;
  2453. }
  2454. //
  2455. // Need to handle network uses;
  2456. //
  2457. return( BytesNeeded/2 );
  2458. }
  2459. BOOL
  2460. WINAPI
  2461. SetVolumeLabelA(
  2462. LPCSTR lpRootPathName,
  2463. LPCSTR lpVolumeName
  2464. )
  2465. {
  2466. PUNICODE_STRING Unicode;
  2467. UNICODE_STRING UnicodeVolumeName;
  2468. BOOL ReturnValue;
  2469. if (!ARGUMENT_PRESENT( lpRootPathName )) {
  2470. lpRootPathName = "\\";
  2471. }
  2472. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  2473. if (Unicode == NULL) {
  2474. return FALSE;
  2475. }
  2476. if ( ARGUMENT_PRESENT(lpVolumeName) ) {
  2477. if (!Basep8BitStringToDynamicUnicodeString( &UnicodeVolumeName, lpVolumeName )) {
  2478. return FALSE;
  2479. }
  2480. } else {
  2481. UnicodeVolumeName.Buffer = NULL;
  2482. }
  2483. ReturnValue = SetVolumeLabelW((LPCWSTR)Unicode->Buffer,(LPCWSTR)UnicodeVolumeName.Buffer);
  2484. RtlFreeUnicodeString(&UnicodeVolumeName);
  2485. return ReturnValue;
  2486. }
  2487. BOOL
  2488. WINAPI
  2489. SetVolumeLabelW(
  2490. LPCWSTR lpRootPathName,
  2491. LPCWSTR lpVolumeName
  2492. )
  2493. {
  2494. NTSTATUS Status;
  2495. OBJECT_ATTRIBUTES Obja;
  2496. HANDLE Handle;
  2497. UNICODE_STRING FileName;
  2498. UNICODE_STRING LabelName;
  2499. IO_STATUS_BLOCK IoStatusBlock;
  2500. BOOLEAN TranslationStatus;
  2501. PVOID FreeBuffer;
  2502. PFILE_FS_LABEL_INFORMATION LabelInformation;
  2503. ULONG LabelInfoLength;
  2504. WCHAR DefaultPath[2];
  2505. BOOL rv;
  2506. WCHAR volumeName[MAX_PATH];
  2507. BOOL usingVolumeName;
  2508. rv = FALSE;
  2509. DefaultPath[0] = (WCHAR)'\\';
  2510. DefaultPath[1] = UNICODE_NULL;
  2511. if ( ARGUMENT_PRESENT(lpVolumeName) ) {
  2512. RtlInitUnicodeString(&LabelName,lpVolumeName);
  2513. }
  2514. else {
  2515. LabelName.Length = 0;
  2516. LabelName.MaximumLength = 0;
  2517. LabelName.Buffer = NULL;
  2518. }
  2519. if (ARGUMENT_PRESENT(lpRootPathName)) {
  2520. if (GetVolumeNameForVolumeMountPointW(lpRootPathName, volumeName,
  2521. MAX_PATH)) {
  2522. usingVolumeName = TRUE;
  2523. } else {
  2524. usingVolumeName = FALSE;
  2525. }
  2526. } else {
  2527. usingVolumeName = FALSE;
  2528. }
  2529. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2530. usingVolumeName ? volumeName : (ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath),
  2531. &FileName,
  2532. NULL,
  2533. NULL
  2534. );
  2535. if ( !TranslationStatus ) {
  2536. SetLastError(ERROR_PATH_NOT_FOUND);
  2537. return FALSE;
  2538. }
  2539. FreeBuffer = FileName.Buffer;
  2540. //
  2541. // Check to make sure a root was specified
  2542. //
  2543. if ( FileName.Buffer[(FileName.Length >> 1)-1] != '\\' ) {
  2544. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2545. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  2546. return FALSE;
  2547. }
  2548. InitializeObjectAttributes(
  2549. &Obja,
  2550. &FileName,
  2551. OBJ_CASE_INSENSITIVE,
  2552. NULL,
  2553. NULL
  2554. );
  2555. //
  2556. // Open the file
  2557. //
  2558. Status = NtOpenFile(
  2559. &Handle,
  2560. (ACCESS_MASK)FILE_WRITE_DATA | SYNCHRONIZE,
  2561. &Obja,
  2562. &IoStatusBlock,
  2563. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2564. FILE_SYNCHRONOUS_IO_NONALERT
  2565. );
  2566. if ( !NT_SUCCESS(Status) ) {
  2567. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2568. BaseSetLastNTError(Status);
  2569. return FALSE;
  2570. }
  2571. if ( !IsThisARootDirectory(Handle,NULL) ) {
  2572. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2573. NtClose(Handle);
  2574. SetLastError(ERROR_DIR_NOT_ROOT);
  2575. return FALSE;
  2576. }
  2577. NtClose(Handle);
  2578. //
  2579. // Now open the volume DASD by ignoring the ending backslash
  2580. //
  2581. FileName.Length -= 2;
  2582. InitializeObjectAttributes(
  2583. &Obja,
  2584. &FileName,
  2585. OBJ_CASE_INSENSITIVE,
  2586. NULL,
  2587. NULL
  2588. );
  2589. //
  2590. // Open the volume
  2591. //
  2592. Status = NtOpenFile(
  2593. &Handle,
  2594. (ACCESS_MASK)FILE_WRITE_DATA | SYNCHRONIZE,
  2595. &Obja,
  2596. &IoStatusBlock,
  2597. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2598. FILE_SYNCHRONOUS_IO_NONALERT
  2599. );
  2600. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2601. if ( !NT_SUCCESS(Status) ) {
  2602. BaseSetLastNTError(Status);
  2603. return FALSE;
  2604. }
  2605. //
  2606. // Set the volume label
  2607. //
  2608. LabelInformation = NULL;
  2609. try {
  2610. rv = TRUE;
  2611. //
  2612. // the label info buffer contains a single wchar that is the basis of
  2613. // the label name. Subtract this out so the info length is the length
  2614. // of the label and the structure (not including the extra wchar)
  2615. //
  2616. if ( LabelName.Length ) {
  2617. LabelInfoLength = sizeof(*LabelInformation) + LabelName.Length - sizeof(WCHAR);
  2618. }
  2619. else {
  2620. LabelInfoLength = sizeof(*LabelInformation);
  2621. }
  2622. LabelInformation = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), LabelInfoLength);
  2623. if ( LabelInformation ) {
  2624. RtlCopyMemory(
  2625. LabelInformation->VolumeLabel,
  2626. LabelName.Buffer,
  2627. LabelName.Length
  2628. );
  2629. LabelInformation->VolumeLabelLength = LabelName.Length;
  2630. Status = NtSetVolumeInformationFile(
  2631. Handle,
  2632. &IoStatusBlock,
  2633. (PVOID) LabelInformation,
  2634. LabelInfoLength,
  2635. FileFsLabelInformation
  2636. );
  2637. if ( !NT_SUCCESS(Status) ) {
  2638. rv = FALSE;
  2639. BaseSetLastNTError(Status);
  2640. }
  2641. }
  2642. else {
  2643. rv = FALSE;
  2644. BaseSetLastNTError(STATUS_NO_MEMORY);
  2645. }
  2646. }
  2647. finally {
  2648. NtClose(Handle);
  2649. if ( LabelInformation ) {
  2650. RtlFreeHeap(RtlProcessHeap(), 0,LabelInformation);
  2651. }
  2652. }
  2653. return rv;
  2654. }
  2655. BOOL
  2656. APIENTRY
  2657. CheckNameLegalDOS8Dot3A(
  2658. IN LPCSTR lpName,
  2659. OUT LPSTR lpOemName OPTIONAL,
  2660. IN DWORD OemNameSize OPTIONAL,
  2661. OUT PBOOL pbNameContainsSpaces OPTIONAL,
  2662. OUT PBOOL pbNameLegal
  2663. )
  2664. /*++
  2665. ANSI thunk to IsNameLegalDOS8Dot3W
  2666. --*/
  2667. {
  2668. ANSI_STRING AnsiStr;
  2669. PUNICODE_STRING pUnicodeStr;
  2670. NTSTATUS Status;
  2671. BOOL Result;
  2672. if( (lpName == NULL) || (pbNameLegal == NULL) ||
  2673. ((lpOemName == NULL) && (OemNameSize != 0)) ||
  2674. (OemNameSize > MAXUSHORT)
  2675. ) {
  2676. SetLastError( ERROR_INVALID_PARAMETER );
  2677. return FALSE;
  2678. }
  2679. pUnicodeStr = Basep8BitStringToStaticUnicodeString( lpName );
  2680. if( pUnicodeStr == NULL ) {
  2681. //
  2682. // LastError already set by Basep8BitStringToStaticUnicodeString
  2683. //
  2684. return FALSE;
  2685. }
  2686. Result = CheckNameLegalDOS8Dot3W(
  2687. (LPCWSTR)(pUnicodeStr->Buffer),
  2688. lpOemName,
  2689. OemNameSize,
  2690. pbNameContainsSpaces,
  2691. pbNameLegal
  2692. );
  2693. return Result;
  2694. }
  2695. BOOL
  2696. APIENTRY
  2697. CheckNameLegalDOS8Dot3W(
  2698. IN LPCWSTR lpName,
  2699. OUT LPSTR lpOemName OPTIONAL,
  2700. IN DWORD OemNameSize OPTIONAL,
  2701. OUT PBOOL pbNameContainsSpaces OPTIONAL,
  2702. OUT PBOOL pbNameLegal
  2703. )
  2704. /*++
  2705. Routine Description:
  2706. This function determines whether this name can successfully be used to
  2707. create a file on the FAT file system.
  2708. This routine can therefore also be used to determine if a name is
  2709. appropriate to be passed back to a Win31 or DOS app, i.e. whether
  2710. the downlevel APP will understand the name.
  2711. Arguments:
  2712. lpName - The UNICODE name to test for conformance to 8.3 symantics.
  2713. lpOemName - If specified, will receive the Oem name corresponding
  2714. to the passed in lpName. Storage must be provided by the caller.
  2715. The name is undefined if the routine returns FALSE or lpName
  2716. does not conform to 8.3 symantics.
  2717. OemNameSize - If lpOemName is specified, then OemNameSize must specify
  2718. the size of the lpOemName buffer in chars. If lpOemName is not
  2719. specified, then OemNameSize must be set to zero.
  2720. pbNameContainsSpaces - If the name is a valid 8.3 FAT name, then this
  2721. parameter will indicate if the names contains spaces. If
  2722. the name is not 8.3 compliant, this parameter is undefined. In
  2723. many instances, the alternate name is more appropriate to
  2724. use if spaces are present in the principle name, even if
  2725. it is 8.3 compliant.
  2726. pbNameLegal - If the function returns TRUE, then this
  2727. parameter will indicate if the passed in UNICODE name forms a valid
  2728. 8.3 FAT name when upcased to the current Oem code page. If
  2729. the name is not 8.3 compliant, this parameter is undefined.
  2730. TRUE - passed in UNICODE name forms a valid 8.3 FAT name
  2731. FALSE - passed in UNICODE name does not forms a valid 8.3 FAT name
  2732. Return Value:
  2733. TRUE - function succeeds
  2734. FALSE - Function fails. Extended error status is available using
  2735. GetLastError.
  2736. --*/
  2737. {
  2738. #define BASEP_LOCAL_OEM_BUFFER_SIZE (12 * sizeof(ANSI_NULL))
  2739. UNICODE_STRING UnicodeStr;
  2740. OEM_STRING OemStr;
  2741. POEM_STRING pOemStr;
  2742. UCHAR OemBuffer[BASEP_LOCAL_OEM_BUFFER_SIZE];
  2743. BOOLEAN SpacesInName, Result;
  2744. if( (lpName == NULL) || (pbNameLegal == NULL) ||
  2745. ((lpOemName == NULL) && (OemNameSize != 0)) ||
  2746. (OemNameSize > MAXUSHORT)
  2747. ) {
  2748. SetLastError( ERROR_INVALID_PARAMETER );
  2749. return FALSE;
  2750. }
  2751. if( lpOemName != NULL ) {
  2752. //
  2753. // Use a local buffer so that RtlIsNameLegalDOS8Dot3 will not fail
  2754. // due to insufficent OemName buffer size
  2755. //
  2756. OemStr.Length = 0;
  2757. OemStr.MaximumLength = BASEP_LOCAL_OEM_BUFFER_SIZE;
  2758. OemStr.Buffer = OemBuffer;
  2759. pOemStr = &OemStr;
  2760. }
  2761. else {
  2762. pOemStr = NULL;
  2763. }
  2764. RtlInitUnicodeString( &UnicodeStr, lpName );
  2765. Result = RtlIsNameLegalDOS8Dot3(
  2766. &UnicodeStr,
  2767. pOemStr,
  2768. &SpacesInName
  2769. );
  2770. if( Result != FALSE ) {
  2771. if( pOemStr != NULL ) {
  2772. if( OemNameSize < (OemStr.Length + sizeof(ANSI_NULL)) ) {
  2773. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2774. return FALSE;
  2775. }
  2776. RtlCopyMemory( lpOemName, OemStr.Buffer, OemStr.Length );
  2777. lpOemName[OemStr.Length/sizeof(ANSI_NULL)] = ANSI_NULL;
  2778. }
  2779. if( pbNameContainsSpaces != NULL ) {
  2780. *pbNameContainsSpaces = SpacesInName;
  2781. }
  2782. }
  2783. *pbNameLegal = Result;
  2784. return TRUE;
  2785. #undef BASEP_LOCAL_OEM_BUFFER_SIZE
  2786. }
  2787. #if 0
  2788. //
  2789. // frankar, let me know if this is needed...
  2790. //
  2791. UINT
  2792. WINAPI
  2793. GetZawSysDirectoryA(
  2794. LPSTR lpBuffer,
  2795. UINT uSize
  2796. )
  2797. {
  2798. ANSI_STRING AnsiString;
  2799. UNICODE_STRING UnicodeString;
  2800. NTSTATUS Status;
  2801. ULONG cbAnsiString;
  2802. UnicodeString.MaximumLength = (USHORT)((uSize<<1)+sizeof(UNICODE_NULL));
  2803. UnicodeString.Buffer = RtlAllocateHeap(
  2804. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2805. UnicodeString.MaximumLength
  2806. );
  2807. if ( !UnicodeString.Buffer ) {
  2808. BaseSetLastNTError(STATUS_NO_MEMORY);
  2809. return 0;
  2810. }
  2811. UnicodeString.Length = (USHORT)GetZawSysDirectoryW(
  2812. UnicodeString.Buffer,
  2813. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
  2814. )*2;
  2815. if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
  2816. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  2817. //
  2818. // given buffer size is too small.
  2819. // allocate enough size of buffer and try again
  2820. //
  2821. // we need to get entire unicode path
  2822. // otherwise we can't figure out the exact length
  2823. // of corresponding ansi string (cbAnsiString).
  2824. UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
  2825. MAKE_TAG( TMP_TAG ),
  2826. UnicodeString.Length+ sizeof(UNICODE_NULL));
  2827. if ( !UnicodeString.Buffer ) {
  2828. BaseSetLastNTError(STATUS_NO_MEMORY);
  2829. return 0;
  2830. }
  2831. UnicodeString.Length = (USHORT)GetZawSysDirectoryW(
  2832. UnicodeString.Buffer,
  2833. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
  2834. ) * 2;
  2835. Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
  2836. UnicodeString.Buffer,
  2837. UnicodeString.Length );
  2838. if ( !NT_SUCCESS(Status) ) {
  2839. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  2840. BaseSetLastNTError(Status);
  2841. return 0;
  2842. }
  2843. else if ( nBufferLength < cbAnsiString ) {
  2844. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  2845. return cbAnsiString;
  2846. }
  2847. }
  2848. AnsiString.Buffer = lpBuffer;
  2849. AnsiString.MaximumLength = (USHORT)(uSize+1);
  2850. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  2851. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  2852. if ( !NT_SUCCESS(Status) ) {
  2853. BaseSetLastNTError(Status);
  2854. return 0;
  2855. }
  2856. return AnsiString.Length;
  2857. }
  2858. UINT
  2859. WINAPI
  2860. GetZawWindDirectoryA(
  2861. LPSTR lpBuffer,
  2862. UINT uSize
  2863. )
  2864. {
  2865. ANSI_STRING AnsiString;
  2866. UNICODE_STRING UnicodeString;
  2867. NTSTATUS Status;
  2868. ULONG cbAnsiString;
  2869. UnicodeString.MaximumLength = (USHORT)((uSize<<1)+sizeof(UNICODE_NULL));
  2870. UnicodeString.Buffer = RtlAllocateHeap(
  2871. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2872. UnicodeString.MaximumLength
  2873. );
  2874. if ( !UnicodeString.Buffer ) {
  2875. BaseSetLastNTError(STATUS_NO_MEMORY);
  2876. return 0;
  2877. }
  2878. UnicodeString.Length = (USHORT)GetZawWindDirectoryW(
  2879. UnicodeString.Buffer,
  2880. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
  2881. )*2;
  2882. if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
  2883. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  2884. //
  2885. // given buffer size is too small.
  2886. // allocate enough size of buffer and try again
  2887. //
  2888. // we need to get entire unicode path
  2889. // otherwise we can't figure out the exact length
  2890. // of corresponding ansi string (cbAnsiString).
  2891. UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
  2892. MAKE_TAG( TMP_TAG ),
  2893. UnicodeString.Length+ sizeof(UNICODE_NULL));
  2894. if ( !UnicodeString.Buffer ) {
  2895. BaseSetLastNTError(STATUS_NO_MEMORY);
  2896. return 0;
  2897. }
  2898. UnicodeString.Length = (USHORT)GetZawWindDirectoryW(
  2899. UnicodeString.Buffer,
  2900. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
  2901. ) * 2;
  2902. Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
  2903. UnicodeString.Buffer,
  2904. UnicodeString.Length );
  2905. if ( !NT_SUCCESS(Status) ) {
  2906. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  2907. BaseSetLastNTError(Status);
  2908. return 0;
  2909. }
  2910. else if ( nBufferLength < cbAnsiString ) {
  2911. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  2912. return cbAnsiString;
  2913. }
  2914. }
  2915. AnsiString.Buffer = lpBuffer;
  2916. AnsiString.MaximumLength = (USHORT)(uSize+1);
  2917. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  2918. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  2919. if ( !NT_SUCCESS(Status) ) {
  2920. BaseSetLastNTError(Status);
  2921. return 0;
  2922. }
  2923. return AnsiString.Length;
  2924. }
  2925. UINT
  2926. WINAPI
  2927. GetZawSysDirectoryW(
  2928. LPWSTR lpBuffer,
  2929. UINT uSize
  2930. )
  2931. {
  2932. NTSTATUS Status;
  2933. HANDLE CurrentUserKey;
  2934. HANDLE DirKey;
  2935. UNICODE_STRING KeyName;
  2936. UNICODE_STRING KeyValueName;
  2937. OBJECT_ATTRIBUTES ObjectAttributes;
  2938. ULONG DataLength;
  2939. ULONG ValueInfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+MAX_PATH/2];
  2940. PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
  2941. Status = RtlOpenCurrentUser(GENERIC_READ,&CurrentUserKey);
  2942. if ( !NT_SUCCESS(Status) ) {
  2943. bail_gzsd:
  2944. return GetSystemDirectoryW(lpBuffer,uSize);
  2945. }
  2946. RtlInitUnicodeString(&KeyName,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ZAW");
  2947. InitializeObjectAttributes( &ObjectAttributes,
  2948. &KeyName,
  2949. OBJ_CASE_INSENSITIVE,
  2950. CurrentUserKey,
  2951. NULL
  2952. );
  2953. Status = NtOpenKey( &DirKey,
  2954. KEY_READ | KEY_NOTIFY | KEY_WRITE,
  2955. &ObjectAttributes
  2956. );
  2957. NtClose(CurrentUserKey);
  2958. if ( !NT_SUCCESS(Status) ) {
  2959. goto bail_gzsd;
  2960. }
  2961. RtlInitUnicodeString(&KeyValueName,L"ZawSys");
  2962. ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&ValueInfoBuffer;
  2963. Status = NtQueryValueKey( DirKey,
  2964. &KeyValueName,
  2965. KeyValuePartialInformation,
  2966. ValueInfo,
  2967. sizeof(ValueInfoBuffer),
  2968. &DataLength
  2969. );
  2970. NtClose(DirKey);
  2971. if ( !NT_SUCCESS(Status) ) {
  2972. goto bail_gzsd;
  2973. }
  2974. if ( ValueInfo->DataLength > (uSize<<1) ) {
  2975. goto bail_gzsd;
  2976. }
  2977. RtlCopyMemory(lpBuffer,ValueInfo->Data,ValueInfo->DataLength);
  2978. return (ValueInfo->DataLength >> 1)-1;
  2979. }
  2980. UINT
  2981. WINAPI
  2982. GetZawWindDirectoryW(
  2983. LPWSTR lpBuffer,
  2984. UINT uSize
  2985. )
  2986. {
  2987. NTSTATUS Status;
  2988. HANDLE CurrentUserKey;
  2989. HANDLE DirKey;
  2990. UNICODE_STRING KeyName;
  2991. UNICODE_STRING KeyValueName;
  2992. OBJECT_ATTRIBUTES ObjectAttributes;
  2993. ULONG DataLength;
  2994. ULONG ValueInfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+MAX_PATH/2];
  2995. PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
  2996. Status = RtlOpenCurrentUser(GENERIC_READ,&CurrentUserKey);
  2997. if ( !NT_SUCCESS(Status) ) {
  2998. bail_gzwd:
  2999. return GetWindowsDirectoryW(lpBuffer,uSize);
  3000. }
  3001. RtlInitUnicodeString(&KeyName,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ZAW");
  3002. InitializeObjectAttributes( &ObjectAttributes,
  3003. &KeyName,
  3004. OBJ_CASE_INSENSITIVE,
  3005. CurrentUserKey,
  3006. NULL
  3007. );
  3008. Status = NtOpenKey( &DirKey,
  3009. KEY_READ | KEY_NOTIFY | KEY_WRITE,
  3010. &ObjectAttributes
  3011. );
  3012. NtClose(CurrentUserKey);
  3013. if ( !NT_SUCCESS(Status) ) {
  3014. goto bail_gzwd;
  3015. }
  3016. RtlInitUnicodeString(&KeyValueName,L"ZawWind");
  3017. ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&ValueInfoBuffer;
  3018. Status = NtQueryValueKey( DirKey,
  3019. &KeyValueName,
  3020. KeyValuePartialInformation,
  3021. ValueInfo,
  3022. sizeof(ValueInfoBuffer),
  3023. &DataLength
  3024. );
  3025. NtClose(DirKey);
  3026. if ( !NT_SUCCESS(Status) ) {
  3027. goto bail_gzwd;
  3028. }
  3029. if ( ValueInfo->DataLength > (uSize<<1) ) {
  3030. goto bail_gzwd;
  3031. }
  3032. RtlCopyMemory(lpBuffer,ValueInfo->Data,ValueInfo->DataLength);
  3033. return (ValueInfo->DataLength >> 1)-1;
  3034. }
  3035. #endif