Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3743 lines
109 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 WCHARs) 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. RtlCopyMemory(
  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. RtlCopyMemory(
  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. RtlCopyMemory(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. RtlCopyMemory(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. NTSTATUS Status;
  732. PWSTR FilePart;
  733. PWSTR *FilePartPtr;
  734. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  735. FilePartPtr = &FilePart;
  736. }
  737. else {
  738. FilePartPtr = NULL;
  739. }
  740. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  741. if (Unicode == NULL) {
  742. return 0;
  743. }
  744. if ( ARGUMENT_PRESENT(lpExtension) ) {
  745. if (!Basep8BitStringToDynamicUnicodeString( &xlpExtension, lpExtension )) {
  746. return 0;
  747. }
  748. } else {
  749. xlpExtension.Buffer = NULL;
  750. }
  751. if ( ARGUMENT_PRESENT(lpPath) ) {
  752. if (!Basep8BitStringToDynamicUnicodeString( &xlpPath, lpPath )) {
  753. if ( ARGUMENT_PRESENT(lpExtension) ) {
  754. RtlFreeUnicodeString(&xlpExtension);
  755. }
  756. return 0;
  757. }
  758. } else {
  759. xlpPath.Buffer = NULL;
  760. }
  761. xlpBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nBufferLength<<1);
  762. if ( !xlpBuffer ) {
  763. BaseSetLastNTError(STATUS_NO_MEMORY);
  764. ReturnValue = 0;
  765. goto bail0;
  766. }
  767. ReturnValue = SearchPathW(
  768. xlpPath.Buffer,
  769. Unicode->Buffer,
  770. xlpExtension.Buffer,
  771. nBufferLength,
  772. xlpBuffer,
  773. FilePartPtr
  774. );
  775. //
  776. // === DBCS modification note [takaok] ===
  777. //
  778. // SearchPathW retruns:
  779. //
  780. // buffer size needed(including null terminator) if buffer size is too small.
  781. // number of characters( not including null terminator) if buffer size is enougth
  782. //
  783. // This means SearchPathW never returns value which is equal to nBufferLength.
  784. //
  785. if ( ReturnValue > nBufferLength ) {
  786. //
  787. // To know the ansi buffer size needed, we should get all of
  788. // unicode string.
  789. //
  790. RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
  791. xlpBuffer = RtlAllocateHeap(RtlProcessHeap(),
  792. MAKE_TAG( TMP_TAG ),
  793. ReturnValue * sizeof(WCHAR));
  794. if ( !xlpBuffer ) {
  795. BaseSetLastNTError(STATUS_NO_MEMORY);
  796. goto bail0;
  797. }
  798. ReturnValue = SearchPathW(
  799. xlpPath.Buffer,
  800. Unicode->Buffer,
  801. xlpExtension.Buffer,
  802. ReturnValue,
  803. xlpBuffer,
  804. FilePartPtr
  805. );
  806. if ( ReturnValue > 0 ) {
  807. //
  808. // We called SearchPathW with the enough size of buffer.
  809. // So, ReturnValue is the size of the path not including the
  810. // terminating null character.
  811. //
  812. Status = RtlUnicodeToMultiByteSize( &ReturnValue,
  813. xlpBuffer,
  814. ReturnValue * sizeof(WCHAR));
  815. if ( !NT_SUCCESS(Status) ) {
  816. BaseSetLastNTError(Status);
  817. ReturnValue = 0;
  818. }
  819. else {
  820. ReturnValue += 1;
  821. }
  822. }
  823. } else if ( ReturnValue > 0 ) {
  824. INT AnsiByteCount;
  825. //
  826. // We have unicode string. We need to compute the ansi byte count
  827. // of the string.
  828. //
  829. // ReturnValue : unicode character count not including null terminator
  830. // AnsiByteCount : ansi byte count not including null terminator
  831. //
  832. Status = RtlUnicodeToMultiByteSize( &AnsiByteCount,
  833. xlpBuffer,
  834. ReturnValue * sizeof(WCHAR) );
  835. if ( !NT_SUCCESS(Status) ) {
  836. BaseSetLastNTError(Status);
  837. ReturnValue = 0;
  838. }
  839. else {
  840. if ( AnsiByteCount < (INT)nBufferLength ) {
  841. //
  842. // The string (including null terminator) fits to the buffer
  843. //
  844. Status = RtlUnicodeToMultiByteN ( lpBuffer,
  845. nBufferLength - 1,
  846. &AnsiByteCount,
  847. xlpBuffer,
  848. ReturnValue * sizeof(WCHAR)
  849. );
  850. if ( !NT_SUCCESS(Status) ) {
  851. BaseSetLastNTError(Status);
  852. ReturnValue = 0;
  853. }
  854. else {
  855. lpBuffer[ AnsiByteCount ] = '\0';
  856. //
  857. // The return value is the byte count copied to the buffer
  858. // not including the terminating null character.
  859. //
  860. ReturnValue = AnsiByteCount;
  861. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  862. if ( FilePart == NULL ) {
  863. *lpFilePart = NULL;
  864. } else {
  865. INT PrefixLength;
  866. PrefixLength = (INT)(FilePart - xlpBuffer);
  867. Status = RtlUnicodeToMultiByteSize( &PrefixLength,
  868. xlpBuffer,
  869. PrefixLength * sizeof(WCHAR));
  870. if ( !NT_SUCCESS(Status) ) {
  871. BaseSetLastNTError(Status);
  872. ReturnValue = 0;
  873. }
  874. else {
  875. *lpFilePart = lpBuffer + PrefixLength;
  876. }
  877. }
  878. }
  879. }
  880. } else {
  881. //
  882. // We should return the size of the buffer required to
  883. // hold the path. The size should include the
  884. // terminating null character.
  885. //
  886. ReturnValue = AnsiByteCount + 1;
  887. }
  888. }
  889. }
  890. RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
  891. bail0:
  892. if ( ARGUMENT_PRESENT(lpExtension) ) {
  893. RtlFreeUnicodeString(&xlpExtension);
  894. }
  895. if ( ARGUMENT_PRESENT(lpPath) ) {
  896. RtlFreeUnicodeString(&xlpPath);
  897. }
  898. return ReturnValue;
  899. }
  900. #ifdef WX86
  901. ULONG
  902. GetFullPathNameWithWx86Override(
  903. PCWSTR lpFileName,
  904. ULONG nBufferLength,
  905. PWSTR lpBuffer,
  906. PWSTR *lpFilePart
  907. )
  908. {
  909. UNICODE_STRING FullPathName, PathUnicode, Wx86PathName;
  910. PUNICODE_STRING FoundFileName;
  911. RTL_PATH_TYPE PathType;
  912. PWSTR FilePart;
  913. ULONG Length, LengthPath;
  914. ULONG PathNameLength;
  915. FullPathName.Buffer = NULL;
  916. Wx86PathName.Buffer = NULL;
  917. if (lpFilePart) {
  918. *lpFilePart = NULL;
  919. }
  920. FullPathName.MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR)) + sizeof(WCHAR);
  921. FullPathName.Length = 0;
  922. FullPathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  923. MAKE_TAG( TMP_TAG ),
  924. FullPathName.MaximumLength
  925. );
  926. if (!FullPathName.Buffer) {
  927. PathNameLength = 0;
  928. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  929. goto WDOExitCleanup;
  930. }
  931. FoundFileName = &FullPathName;
  932. PathNameLength = RtlGetFullPathName_U(lpFileName,
  933. FullPathName.MaximumLength,
  934. FullPathName.Buffer,
  935. &FilePart
  936. );
  937. if (!PathNameLength || PathNameLength >= FullPathName.MaximumLength) {
  938. PathNameLength = 0;
  939. goto WDOExitCleanup;
  940. }
  941. FullPathName.Length = (USHORT)PathNameLength;
  942. PathUnicode = FullPathName;
  943. PathUnicode.Length = (USHORT)((ULONG_PTR)FilePart -
  944. (ULONG_PTR)FullPathName.Buffer);
  945. PathUnicode.Length -= sizeof(WCHAR);
  946. if (!RtlEqualUnicodeString(&PathUnicode, &BaseWindowsSystemDirectory, TRUE)) {
  947. goto WDOExitCleanup;
  948. }
  949. Wx86PathName.MaximumLength = BaseWindowsSys32x86Directory.Length +
  950. FullPathName.Length - PathUnicode.Length +
  951. 2*sizeof(WCHAR);
  952. Wx86PathName.Length = 0;
  953. Wx86PathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  954. MAKE_TAG( TMP_TAG ),
  955. Wx86PathName.MaximumLength
  956. );
  957. if (!Wx86PathName.Buffer) {
  958. goto WDOExitCleanup;
  959. }
  960. RtlCopyUnicodeString(&Wx86PathName, &BaseWindowsSys32x86Directory);
  961. Length = Wx86PathName.Length + sizeof(WCHAR);
  962. RtlAppendUnicodeToString (&Wx86PathName, FilePart - 1);
  963. if (RtlDoesFileExists_U(Wx86PathName.Buffer)) {
  964. FoundFileName = &Wx86PathName;
  965. FilePart = Wx86PathName.Buffer + Length/sizeof(WCHAR);
  966. }
  967. WDOExitCleanup:
  968. if (PathNameLength) {
  969. if (FoundFileName->Length >= nBufferLength) {
  970. PathNameLength = FoundFileName->Length + sizeof(WCHAR);
  971. }
  972. else {
  973. RtlMoveMemory(lpBuffer,
  974. FoundFileName->Buffer,
  975. FoundFileName->Length + sizeof(WCHAR)
  976. );
  977. PathNameLength = FoundFileName->Length;
  978. Length = (ULONG)(FilePart - FoundFileName->Buffer);
  979. if (lpFilePart) {
  980. *lpFilePart = lpBuffer + Length/sizeof(WCHAR);
  981. }
  982. }
  983. }
  984. if (FullPathName.Buffer) {
  985. RtlFreeHeap(RtlProcessHeap(), 0, FullPathName.Buffer);
  986. }
  987. if (Wx86PathName.Buffer) {
  988. RtlFreeHeap(RtlProcessHeap(), 0, Wx86PathName.Buffer);
  989. }
  990. return PathNameLength;
  991. }
  992. #endif
  993. DWORD
  994. APIENTRY
  995. SearchPathW(
  996. LPCWSTR lpPath,
  997. LPCWSTR lpFileName,
  998. LPCWSTR lpExtension,
  999. DWORD nBufferLength,
  1000. LPWSTR lpBuffer,
  1001. LPWSTR *lpFilePart
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. This function is used to search for a file specifying a search path
  1006. and a filename. It returns with a fully qualified pathname of the
  1007. found file.
  1008. This function is used to locate a file using the specified path. If
  1009. the file is found, its fully qualified pathname is returned. In
  1010. addition to this, it calculates the address of the file name portion
  1011. of the fully qualified pathname.
  1012. Arguments:
  1013. lpPath - An optional parameter, that if specified, supplies the
  1014. search path to be used when locating the file. If this
  1015. parameter is not specified, the default windows search path is
  1016. used. The default path is:
  1017. - The current directory
  1018. - The windows directory
  1019. - The windows system directory
  1020. - The directories listed in the path environment variable
  1021. lpFileName - Supplies the file name of the file to search for.
  1022. lpExtension - An optional parameter, that if specified, supplies an
  1023. extension to be added to the filename when doing the search.
  1024. The extension is only added if the specified filename does not
  1025. end with an extension.
  1026. nBufferLength - Supplies the length in characters of the buffer that
  1027. is to receive the fully qualified path.
  1028. lpBuffer - Returns the fully qualified pathname corresponding to the
  1029. file that was found.
  1030. lpFilePart - Returns the address of the last component of the fully
  1031. qualified pathname.
  1032. Return Value:
  1033. The return value is the length of the string copied to lpBuffer, not
  1034. including the terminating null character. If the return value is
  1035. greater than nBufferLength, the return value is the size of the buffer
  1036. required to hold the pathname. The return value is zero if the
  1037. function failed.
  1038. --*/
  1039. {
  1040. UNICODE_STRING Path;
  1041. UNICODE_STRING FileName;
  1042. UNICODE_STRING DefaultExtension;
  1043. UNICODE_STRING CallersBuffer;
  1044. LPWSTR AllocatedPath = NULL;
  1045. SIZE_T BytesRequired = 0;
  1046. SIZE_T FilePartPrefixCch = 0;
  1047. NTSTATUS Status;
  1048. DWORD dwReturnValue = 0;
  1049. //
  1050. // The guts of this function are now in common ntdll code; however the win32 search
  1051. // path has a few interesting differences from the ntdll search path code. First, it
  1052. // does not search the path if the filename is ".\foo" or "..\foo" and second, when the
  1053. // filename passed in is not a relative path but the file is not found, the default
  1054. // extension is applied regardless of whether the existing filename has an extension.
  1055. //
  1056. // These flags enable those feature-compatibility modes.
  1057. //
  1058. ULONG SearchPathFlags =
  1059. RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH |
  1060. RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION;
  1061. if (lpFilePart != NULL)
  1062. *lpFilePart = NULL;
  1063. Path.Buffer = NULL;
  1064. RtlInitUnicodeString(&FileName, lpFileName);
  1065. //
  1066. // trim trailing spaces, and then check for a real filelength
  1067. // if length is 0 (NULL, "", or " ") passed in then abort the
  1068. // search
  1069. //
  1070. while ((FileName.Length >= sizeof(WCHAR)) &&
  1071. (FileName.Buffer[(FileName.Length / sizeof(WCHAR)) - 1] == L' '))
  1072. FileName.Length -= sizeof(WCHAR);
  1073. if (FileName.Length == 0) {
  1074. SetLastError(ERROR_INVALID_PARAMETER);
  1075. goto Exit;
  1076. }
  1077. RtlInitUnicodeString(&DefaultExtension, lpExtension);
  1078. if ( !ARGUMENT_PRESENT(lpPath) ) {
  1079. SIZE_T Cch;
  1080. Path.Buffer = BaseComputeProcessSearchPath();
  1081. if (Path.Buffer == NULL) {
  1082. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1083. goto Exit;
  1084. }
  1085. Cch = lstrlenW(Path.Buffer);
  1086. if (Cch > UNICODE_STRING_MAX_CHARS) {
  1087. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1088. goto Exit;
  1089. }
  1090. Path.Length = (USHORT) (Cch * sizeof(WCHAR));
  1091. Path.MaximumLength = Path.Length;
  1092. SearchPathFlags |= RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION;
  1093. } else {
  1094. Status = RtlInitUnicodeStringEx(&Path, lpPath);
  1095. if (NT_ERROR(Status)) {
  1096. BaseSetLastNTError(Status);
  1097. goto Exit;
  1098. }
  1099. }
  1100. CallersBuffer.Length = 0;
  1101. if (nBufferLength > UNICODE_STRING_MAX_CHARS) {
  1102. CallersBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
  1103. } else {
  1104. CallersBuffer.MaximumLength = (USHORT) (nBufferLength * sizeof(WCHAR));
  1105. }
  1106. CallersBuffer.Buffer = lpBuffer;
  1107. Status = RtlDosSearchPath_Ustr(
  1108. SearchPathFlags,
  1109. &Path,
  1110. &FileName,
  1111. &DefaultExtension,
  1112. &CallersBuffer,
  1113. NULL, // dynamicstring
  1114. NULL, // fullfilenameout
  1115. &FilePartPrefixCch,
  1116. &BytesRequired);
  1117. if (NT_ERROR(Status)) {
  1118. #if DBG
  1119. // Don't bother with debug spew for the two common expected cases.
  1120. if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL)) {
  1121. DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n", __FUNCTION__, &FileName, Status);
  1122. DbgPrint(" Path = %wZ\n", &Path);
  1123. }
  1124. #endif // DBG
  1125. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1126. SIZE_T CchRequired = BytesRequired / sizeof(WCHAR);
  1127. if (CchRequired > 0xffffffff) {
  1128. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1129. goto Exit;
  1130. }
  1131. dwReturnValue = (DWORD) CchRequired;
  1132. goto Exit;
  1133. }
  1134. // Only set the last error if it wasn't an insufficient buffer; this is just preserving
  1135. // Windows 2000 behavior.
  1136. BaseSetLastNTError(Status);
  1137. goto Exit;
  1138. }
  1139. #ifdef WX86
  1140. if (UseKnownWx86Dll) {
  1141. WCHAR TempBuffer[MAX_PATH];
  1142. RtlCopyMemory(TempBuffer, lpBuffer, CallersBuffer.Length);
  1143. TempBuffer[CallersBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
  1144. dwReturnValue = GetFullPathNameWithWx86Override(
  1145. TempBuffer,
  1146. nBufferLength,
  1147. lpBuffer,
  1148. lpFilePart
  1149. );
  1150. goto Exit;
  1151. } else if (lpFilePart != NULL) {
  1152. *lpFilePart = lpBuffer + FilePartPrefixCch;
  1153. }
  1154. #else
  1155. if (lpFilePart != NULL) {
  1156. *lpFilePart = lpBuffer + FilePartPrefixCch;
  1157. }
  1158. #endif // WX86
  1159. dwReturnValue = CallersBuffer.Length / sizeof(WCHAR);
  1160. Exit:
  1161. if ((Path.Buffer != lpPath) && (Path.Buffer != NULL))
  1162. RtlFreeHeap(RtlProcessHeap(), 0, Path.Buffer);
  1163. return dwReturnValue;
  1164. }
  1165. DWORD
  1166. APIENTRY
  1167. GetTempPathA(
  1168. DWORD nBufferLength,
  1169. LPSTR lpBuffer
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. ANSI thunk to GetTempPathW
  1174. --*/
  1175. {
  1176. ANSI_STRING AnsiString;
  1177. UNICODE_STRING UnicodeString;
  1178. NTSTATUS Status;
  1179. ULONG cbAnsiString;
  1180. UnicodeString.MaximumLength = (USHORT)((nBufferLength<<1)+sizeof(UNICODE_NULL));
  1181. UnicodeString.Buffer = RtlAllocateHeap(
  1182. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  1183. UnicodeString.MaximumLength
  1184. );
  1185. if ( !UnicodeString.Buffer ) {
  1186. BaseSetLastNTError(STATUS_NO_MEMORY);
  1187. return 0;
  1188. }
  1189. UnicodeString.Length = (USHORT)GetTempPathW(
  1190. (DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
  1191. UnicodeString.Buffer
  1192. )*2;
  1193. if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
  1194. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  1195. //
  1196. // given buffer size is too small.
  1197. // allocate enough size of buffer and try again
  1198. //
  1199. // we need to get entire unicode temporary path
  1200. // otherwise we can't figure out the exact length
  1201. // of corresponding ansi string (cbAnsiString).
  1202. UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
  1203. MAKE_TAG( TMP_TAG ),
  1204. UnicodeString.Length+ sizeof(UNICODE_NULL));
  1205. if ( !UnicodeString.Buffer ) {
  1206. BaseSetLastNTError(STATUS_NO_MEMORY);
  1207. return 0;
  1208. }
  1209. UnicodeString.Length = (USHORT)GetTempPathW(
  1210. (DWORD)(UnicodeString.Length)/2,
  1211. UnicodeString.Buffer) * 2;
  1212. Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
  1213. UnicodeString.Buffer,
  1214. UnicodeString.Length );
  1215. if ( !NT_SUCCESS(Status) ) {
  1216. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  1217. BaseSetLastNTError(Status);
  1218. return 0;
  1219. }
  1220. else if ( nBufferLength <= cbAnsiString ) {
  1221. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
  1222. return cbAnsiString + sizeof(ANSI_NULL);
  1223. }
  1224. }
  1225. AnsiString.Buffer = lpBuffer;
  1226. AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
  1227. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  1228. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
  1229. if ( !NT_SUCCESS(Status) ) {
  1230. BaseSetLastNTError(Status);
  1231. return 0;
  1232. }
  1233. return AnsiString.Length;
  1234. }
  1235. DWORD
  1236. APIENTRY
  1237. GetTempPathW(
  1238. DWORD nBufferLength,
  1239. LPWSTR lpBuffer
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. This function is used to return the pathname of the directory that
  1244. should be used to create temporary files.
  1245. Arguments:
  1246. nBufferLength - Supplies the length in bytes of the buffer that is
  1247. to receive the temporary file path.
  1248. lpBuffer - Returns the pathname of the directory that should be used
  1249. to create temporary files in.
  1250. Return Value:
  1251. The return value is the length of the string copied to lpBuffer, not
  1252. including the terminating null character. If the return value is
  1253. greater than nSize, the return value is the size of the buffer
  1254. required to hold the pathname. The return value is zero if the
  1255. function failed.
  1256. --*/
  1257. {
  1258. return BasepGetTempPathW(0, nBufferLength, lpBuffer);
  1259. }
  1260. DWORD
  1261. APIENTRY
  1262. BasepGetTempPathW(
  1263. ULONG Flags,
  1264. DWORD nBufferLength,
  1265. LPWSTR lpBuffer
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. This function is used to return the pathname of the directory that
  1270. should be used to create temporary files.
  1271. Arguments:
  1272. nBufferLength - Supplies the length in bytes of the buffer that is
  1273. to receive the temporary file path.
  1274. lpBuffer - Returns the pathname of the directory that should be used
  1275. to create temporary files in.
  1276. Flags -
  1277. Return Value:
  1278. The return value is the length of the string copied to lpBuffer, not
  1279. including the terminating null character. If the return value is
  1280. greater than nSize, the return value is the size of the buffer
  1281. required to hold the pathname. The return value is zero if the
  1282. function failed.
  1283. --*/
  1284. {
  1285. DWORD Length;
  1286. BOOLEAN AddTrailingSlash;
  1287. UNICODE_STRING EnvironmentValue;
  1288. NTSTATUS Status;
  1289. LPWSTR Name;
  1290. ULONG Position;
  1291. DWORD ReturnLength;
  1292. if (
  1293. (Flags & ~BASEP_GET_TEMP_PATH_PRESERVE_TEB) != 0
  1294. ) {
  1295. BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
  1296. return 0;
  1297. }
  1298. //
  1299. // Some apps don't work with the new long path for the temp directory
  1300. //
  1301. if (APPCOMPATFLAG(KACF_GETTEMPPATH)) {
  1302. #define OLD_TEMP_PATH L"c:\\temp\\"
  1303. #define OLD_TEMP_PATH_SIZE (sizeof(OLD_TEMP_PATH) / sizeof(WCHAR))
  1304. BOOL bRet;
  1305. //
  1306. // If there isn't enough space provided in the buffer return
  1307. // the desired size.
  1308. //
  1309. if (nBufferLength < OLD_TEMP_PATH_SIZE) {
  1310. return OLD_TEMP_PATH_SIZE;
  1311. }
  1312. wcscpy(lpBuffer, OLD_TEMP_PATH);
  1313. //
  1314. // Use the correct drive letter
  1315. //
  1316. lpBuffer[0] = BaseWindowsDirectory.Buffer[0];
  1317. bRet = CreateDirectoryW(lpBuffer, NULL);
  1318. if (!bRet) {
  1319. if (GetLastError() != ERROR_ALREADY_EXISTS)
  1320. return 0;
  1321. }
  1322. return OLD_TEMP_PATH_SIZE - 1;
  1323. }
  1324. nBufferLength *= 2;
  1325. EnvironmentValue = NtCurrentTeb()->StaticUnicodeString;
  1326. if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
  1327. EnvironmentValue.Buffer = (PWSTR)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), EnvironmentValue.MaximumLength);
  1328. if (EnvironmentValue.Buffer == NULL) {
  1329. BaseSetLastNTError(STATUS_NO_MEMORY);
  1330. return 0;
  1331. }
  1332. }
  1333. ReturnLength = 0;
  1334. __try {
  1335. AddTrailingSlash = FALSE;
  1336. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTmpVariableName,&EnvironmentValue);
  1337. if ( !NT_SUCCESS(Status) ) {
  1338. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTempVariableName,&EnvironmentValue);
  1339. if ( !NT_SUCCESS(Status) ) {
  1340. Status = RtlQueryEnvironmentVariable_U(NULL,&BaseUserProfileVariableName,&EnvironmentValue);
  1341. }
  1342. }
  1343. if ( NT_SUCCESS(Status) ) {
  1344. Name = EnvironmentValue.Buffer;
  1345. if ( Name[(EnvironmentValue.Length>>1)-1] != (WCHAR)'\\' ) {
  1346. AddTrailingSlash = TRUE;
  1347. }
  1348. }
  1349. else {
  1350. Name = BaseWindowsDirectory.Buffer;
  1351. if ( Name[(BaseWindowsDirectory.Length>>1)-1] != (WCHAR)'\\' ) {
  1352. AddTrailingSlash = TRUE;
  1353. }
  1354. }
  1355. Length = RtlGetFullPathName_U(
  1356. Name,
  1357. nBufferLength,
  1358. lpBuffer,
  1359. NULL
  1360. );
  1361. Position = Length>>1;
  1362. //
  1363. // Make sure there is room for a trailing back slash
  1364. //
  1365. if ( Length && Length < nBufferLength ) {
  1366. if ( lpBuffer[Position-1] != '\\' ) {
  1367. if ( Length+sizeof((WCHAR)'\\') < nBufferLength ) {
  1368. lpBuffer[Position] = (WCHAR)'\\';
  1369. lpBuffer[Position+1] = UNICODE_NULL;
  1370. ReturnLength = (Length+sizeof((WCHAR)'\\'))/2;
  1371. __leave;
  1372. }
  1373. else {
  1374. ReturnLength = (Length+sizeof((WCHAR)'\\')+sizeof(UNICODE_NULL))/2;
  1375. __leave;
  1376. }
  1377. }
  1378. else {
  1379. ReturnLength = Length/2;
  1380. __leave;
  1381. }
  1382. }
  1383. else {
  1384. if ( AddTrailingSlash ) {
  1385. Length += sizeof((WCHAR)'\\');
  1386. }
  1387. ReturnLength = Length/2;
  1388. __leave;
  1389. }
  1390. }
  1391. __finally {
  1392. if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
  1393. RtlFreeHeap(RtlProcessHeap(), 0, EnvironmentValue.Buffer);
  1394. }
  1395. }
  1396. return ReturnLength;
  1397. }
  1398. UINT
  1399. APIENTRY
  1400. GetTempFileNameA(
  1401. LPCSTR lpPathName,
  1402. LPCSTR lpPrefixString,
  1403. UINT uUnique,
  1404. LPSTR lpTempFileName
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. ANSI thunk to GetTempFileNameW
  1409. --*/
  1410. {
  1411. PUNICODE_STRING Unicode;
  1412. UNICODE_STRING UnicodePrefix;
  1413. NTSTATUS Status;
  1414. UINT ReturnValue;
  1415. UNICODE_STRING UnicodeResult;
  1416. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
  1417. if (Unicode == NULL) {
  1418. return 0;
  1419. }
  1420. if (!Basep8BitStringToDynamicUnicodeString( &UnicodePrefix, lpPrefixString )) {
  1421. return 0;
  1422. }
  1423. UnicodeResult.MaximumLength = (USHORT)((MAX_PATH<<1));
  1424. UnicodeResult.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeResult.MaximumLength);
  1425. if ( !UnicodeResult.Buffer ) {
  1426. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1427. RtlFreeUnicodeString(&UnicodePrefix);
  1428. return 0;
  1429. }
  1430. ReturnValue = GetTempFileNameW(
  1431. Unicode->Buffer,
  1432. UnicodePrefix.Buffer,
  1433. uUnique,
  1434. UnicodeResult.Buffer
  1435. );
  1436. if ( ReturnValue ) {
  1437. ANSI_STRING AnsiString;
  1438. RtlInitUnicodeString(&UnicodeResult,UnicodeResult.Buffer);
  1439. AnsiString.Buffer = lpTempFileName;
  1440. AnsiString.MaximumLength = MAX_PATH;
  1441. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeResult,FALSE);
  1442. if ( !NT_SUCCESS(Status) ) {
  1443. BaseSetLastNTError(Status);
  1444. ReturnValue = 0;
  1445. }
  1446. }
  1447. RtlFreeUnicodeString(&UnicodePrefix);
  1448. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeResult.Buffer);
  1449. return ReturnValue;
  1450. }
  1451. UINT
  1452. APIENTRY
  1453. GetTempFileNameW(
  1454. LPCWSTR lpPathName,
  1455. LPCWSTR lpPrefixString,
  1456. UINT uUnique,
  1457. LPWSTR lpTempFileName
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. This function creates a temporary filename of the following form:
  1462. drive:\path\prefixuuuu.tmp
  1463. In this syntax line, drive:\path\ is the path specified by the
  1464. lpPathName parameter; prefix is all the letters (up to the first
  1465. three) of the string pointed to by the lpPrefixString parameter; and
  1466. uuuu is the hexadecimal value of the number specified by the
  1467. uUnique parameter.
  1468. To avoid problems resulting from converting OEM character an string
  1469. to an ANSI string, an application should call the CreateFile
  1470. function to create the temporary file.
  1471. If the uUnique parameter is zero, GetTempFileName attempts to form a
  1472. unique number based on the current system time. If a file with the
  1473. resulting filename exists, the number is increased by one and the
  1474. test for existence is repeated. This continues until a unique
  1475. filename is found; GetTempFileName then creates a file by that name
  1476. and closes it. No attempt is made to create and open the file when
  1477. uUnique is nonzero.
  1478. Arguments:
  1479. lpPathName - Specifies the null terminated pathname of the directory
  1480. to create the temporary file within.
  1481. lpPrefixString - Points to a null-terminated character string to be
  1482. used as the temporary filename prefix. This string must consist
  1483. of characters in the OEM-defined character set.
  1484. uUnique - Specifies an unsigned integer.
  1485. lpTempFileName - Points to the buffer that is to receive the
  1486. temporary filename. This string consists of characters in the
  1487. OEM-defined character set. This buffer should be at least MAX_PATH
  1488. characters in length to allow sufficient room for the pathname.
  1489. Return Value:
  1490. The return value specifies a unique numeric value used in the
  1491. temporary filename. If a nonzero value was given for the uUnique
  1492. parameter, the return value specifies this same number.
  1493. --*/
  1494. {
  1495. #if !defined(BUILD_WOW6432)
  1496. BASE_API_MSG m;
  1497. PBASE_GETTEMPFILE_MSG a = &m.u.GetTempFile;
  1498. #endif
  1499. LPWSTR p,savedp;
  1500. ULONG Length;
  1501. HANDLE FileHandle;
  1502. ULONG PassCount;
  1503. DWORD LastError;
  1504. UNICODE_STRING UnicodePath, UnicodePrefix;
  1505. CHAR UniqueAsAnsi[8];
  1506. CHAR *c;
  1507. ULONG i;
  1508. #if defined(BUILD_WOW6432)
  1509. UINT uNewUnique;
  1510. #endif
  1511. PassCount = 0;
  1512. RtlInitUnicodeString(&UnicodePath,lpPathName);
  1513. Length = UnicodePath.Length;
  1514. if ( !Length || lpPathName[(Length>>1)-1] != (WCHAR)'\\' ) {
  1515. Length += sizeof(UNICODE_NULL);
  1516. }
  1517. // Length is the number of bytes of data in lpPathName, *not*
  1518. // including the trailing NULL but including the whack.
  1519. // 12 is the number of characters we might append, including the
  1520. // trailing NULL but not including the whack -- preXXXX.tmp\0.
  1521. if (Length > ((MAX_PATH - 12) * sizeof(WCHAR))) {
  1522. SetLastError(ERROR_BUFFER_OVERFLOW);
  1523. return FALSE;
  1524. }
  1525. if (lpTempFileName != lpPathName) {
  1526. // N.B. Must use RtlMoveMemory here -- some callers depend on
  1527. // lpPathName and lpTempFileName overlapping.
  1528. RtlMoveMemory(lpTempFileName,lpPathName,UnicodePath.Length);
  1529. }
  1530. lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
  1531. i = GetFileAttributesW(lpTempFileName);
  1532. if (i == 0xFFFFFFFF) {
  1533. lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
  1534. lpTempFileName[(Length>>1)] = UNICODE_NULL;
  1535. i = GetFileAttributesW(lpTempFileName);
  1536. lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
  1537. }
  1538. if ( (i == 0xFFFFFFFF) ||
  1539. !(i & FILE_ATTRIBUTE_DIRECTORY) ) {
  1540. SetLastError(ERROR_DIRECTORY);
  1541. return FALSE;
  1542. }
  1543. lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
  1544. RtlInitUnicodeString(&UnicodePrefix,lpPrefixString);
  1545. if ( UnicodePrefix.Length > (USHORT)6 ) {
  1546. UnicodePrefix.Length = (USHORT)6;
  1547. }
  1548. p = &lpTempFileName[Length>>1];
  1549. Length = UnicodePrefix.Length;
  1550. RtlMoveMemory(p,lpPrefixString,Length);
  1551. p += (Length>>1);
  1552. savedp = p;
  1553. //
  1554. // If uUnique is not specified, then get one
  1555. //
  1556. uUnique = uUnique & 0x0000ffff;
  1557. try_again:
  1558. p = savedp;
  1559. if ( !uUnique ) {
  1560. #if defined(BUILD_WOW6432)
  1561. uNewUnique = CsrBasepGetTempFile();
  1562. if ( uNewUnique == 0 ) {
  1563. #else
  1564. CsrClientCallServer( (PCSR_API_MSG)&m,
  1565. NULL,
  1566. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1567. BasepGetTempFile
  1568. ),
  1569. sizeof( *a )
  1570. );
  1571. a->uUnique = (UINT)m.ReturnValue;
  1572. if ( m.ReturnValue == 0 ) {
  1573. #endif
  1574. PassCount++;
  1575. if ( PassCount & 0xffff0000 ) {
  1576. return 0;
  1577. }
  1578. goto try_again;
  1579. }
  1580. } else {
  1581. #if defined(BUILD_WOW6432)
  1582. uNewUnique = uUnique;
  1583. #else
  1584. a->uUnique = uUnique;
  1585. #endif
  1586. }
  1587. //
  1588. // Convert the unique value to a 4 byte character string
  1589. //
  1590. #if defined(BUILD_WOW6432)
  1591. RtlIntegerToChar ((ULONG) uNewUnique,16,5,UniqueAsAnsi);
  1592. #else
  1593. RtlIntegerToChar ((ULONG) a->uUnique,16,5,UniqueAsAnsi);
  1594. #endif
  1595. c = UniqueAsAnsi;
  1596. for(i=0;i<4;i++){
  1597. *p = RtlAnsiCharToUnicodeChar(&c);
  1598. if ( *p == UNICODE_NULL ) {
  1599. break;
  1600. }
  1601. p++;
  1602. }
  1603. RtlMoveMemory(p,BaseDotTmpSuffixName.Buffer,BaseDotTmpSuffixName.MaximumLength);
  1604. if ( !uUnique ) {
  1605. //
  1606. // test for resulting name being a device (prefix com, uUnique 1-9...
  1607. //
  1608. if ( RtlIsDosDeviceName_U(lpTempFileName) ) {
  1609. PassCount++;
  1610. if ( PassCount & 0xffff0000 ) {
  1611. SetLastError(ERROR_INVALID_NAME);
  1612. return 0;
  1613. }
  1614. goto try_again;
  1615. }
  1616. FileHandle = CreateFileW(
  1617. lpTempFileName,
  1618. GENERIC_READ,
  1619. 0,
  1620. NULL,
  1621. CREATE_NEW,
  1622. FILE_ATTRIBUTE_NORMAL,
  1623. NULL
  1624. );
  1625. //
  1626. // If the create worked, then we are ok. Just close the file.
  1627. // Otherwise, try again.
  1628. //
  1629. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  1630. NtClose(FileHandle);
  1631. } else {
  1632. //
  1633. // NTRAID#60021-2002/03/14-earhart: This test should be
  1634. // inverted when time permits sufficient testing to nail
  1635. // down the error codes that would indicate is is
  1636. // reasonable to continue the loop as opposed to stop the
  1637. // loop. All it currently takes is CreateFile coming back
  1638. // with an error we don't know about to make us spin here
  1639. // for a long time.
  1640. //
  1641. LastError = GetLastError();
  1642. switch (LastError) {
  1643. case ERROR_INVALID_PARAMETER :
  1644. case ERROR_WRITE_PROTECT :
  1645. case ERROR_FILE_NOT_FOUND :
  1646. case ERROR_BAD_PATHNAME :
  1647. case ERROR_INVALID_NAME :
  1648. case ERROR_PATH_NOT_FOUND :
  1649. case ERROR_NETWORK_ACCESS_DENIED :
  1650. case ERROR_DISK_CORRUPT :
  1651. case ERROR_FILE_CORRUPT :
  1652. case ERROR_DISK_FULL :
  1653. case ERROR_CANNOT_MAKE :
  1654. return 0;
  1655. case ERROR_ACCESS_DENIED :
  1656. // It's possible for us to hit this if there's a
  1657. // directory with the name we're trying; in that
  1658. // case, we can usefully continue.
  1659. // CreateFile() uses BaseSetLastNTError() to set
  1660. // LastStatusValue to the actual NT error in the
  1661. // TEB; we just need to check it, and only abort
  1662. // if it's not a directory.
  1663. // This was bug #397477.
  1664. if (NtCurrentTeb()->LastStatusValue
  1665. != STATUS_FILE_IS_A_DIRECTORY)
  1666. return 0;
  1667. }
  1668. PassCount++;
  1669. if ( PassCount & 0xffff0000 ) {
  1670. return 0;
  1671. }
  1672. goto try_again;
  1673. }
  1674. }
  1675. #if defined(BUILD_WOW6432)
  1676. return uNewUnique;
  1677. #else
  1678. return a->uUnique;
  1679. #endif
  1680. }
  1681. BOOL
  1682. APIENTRY
  1683. GetDiskFreeSpaceA(
  1684. LPCSTR lpRootPathName,
  1685. LPDWORD lpSectorsPerCluster,
  1686. LPDWORD lpBytesPerSector,
  1687. LPDWORD lpNumberOfFreeClusters,
  1688. LPDWORD lpTotalNumberOfClusters
  1689. )
  1690. /*++
  1691. Routine Description:
  1692. ANSI thunk to GetDiskFreeSpaceW
  1693. --*/
  1694. {
  1695. PUNICODE_STRING Unicode;
  1696. if (!ARGUMENT_PRESENT( lpRootPathName )) {
  1697. lpRootPathName = "\\";
  1698. }
  1699. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  1700. if (Unicode == NULL) {
  1701. return FALSE;
  1702. }
  1703. return ( GetDiskFreeSpaceW(
  1704. (LPCWSTR)Unicode->Buffer,
  1705. lpSectorsPerCluster,
  1706. lpBytesPerSector,
  1707. lpNumberOfFreeClusters,
  1708. lpTotalNumberOfClusters
  1709. )
  1710. );
  1711. }
  1712. BOOL
  1713. APIENTRY
  1714. GetDiskFreeSpaceW(
  1715. LPCWSTR lpRootPathName,
  1716. LPDWORD lpSectorsPerCluster,
  1717. LPDWORD lpBytesPerSector,
  1718. LPDWORD lpNumberOfFreeClusters,
  1719. LPDWORD lpTotalNumberOfClusters
  1720. )
  1721. #define MAKE2GFRIENDLY(lpOut, dwSize) \
  1722. \
  1723. if (!bAppHack) { \
  1724. *lpOut = dwSize; \
  1725. } else { \
  1726. dwTemp = SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector; \
  1727. \
  1728. if (0x7FFFFFFF / dwTemp < dwSize) { \
  1729. \
  1730. *lpOut = 0x7FFFFFFF / dwTemp; \
  1731. } else { \
  1732. *lpOut = dwSize; \
  1733. } \
  1734. }
  1735. /*++
  1736. Routine Description:
  1737. The free space on a disk and the size parameters can be returned
  1738. using GetDiskFreeSpace.
  1739. Arguments:
  1740. lpRootPathName - An optional parameter, that if specified, supplies
  1741. the root directory of the disk whose free space is to be
  1742. returned for. If this parameter is not specified, then the root
  1743. of the current directory is used.
  1744. lpSectorsPerCluster - Returns the number of sectors per cluster
  1745. where a cluster is the allocation granularity on the disk.
  1746. lpBytesPerSector - Returns the number of bytes per sector.
  1747. lpNumberOfFreeClusters - Returns the total number of free clusters
  1748. on the disk.
  1749. lpTotalNumberOfClusters - Returns the total number of clusters on
  1750. the disk.
  1751. Return Value:
  1752. TRUE - The operation was successful.
  1753. FALSE/NULL - The operation failed. Extended error status is available
  1754. using GetLastError.
  1755. --*/
  1756. {
  1757. NTSTATUS Status;
  1758. OBJECT_ATTRIBUTES Obja;
  1759. HANDLE Handle;
  1760. UNICODE_STRING FileName;
  1761. IO_STATUS_BLOCK IoStatusBlock;
  1762. BOOLEAN TranslationStatus;
  1763. PVOID FreeBuffer;
  1764. FILE_FS_SIZE_INFORMATION SizeInfo;
  1765. WCHAR DefaultPath[2];
  1766. DWORD dwTemp;
  1767. BOOL bAppHack;
  1768. DefaultPath[0] = (WCHAR)'\\';
  1769. DefaultPath[1] = UNICODE_NULL;
  1770. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1771. ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
  1772. &FileName,
  1773. NULL,
  1774. NULL
  1775. );
  1776. if ( !TranslationStatus ) {
  1777. SetLastError(ERROR_PATH_NOT_FOUND);
  1778. return FALSE;
  1779. }
  1780. FreeBuffer = FileName.Buffer;
  1781. InitializeObjectAttributes(
  1782. &Obja,
  1783. &FileName,
  1784. OBJ_CASE_INSENSITIVE,
  1785. NULL,
  1786. NULL
  1787. );
  1788. //
  1789. // Open the file
  1790. //
  1791. Status = NtOpenFile(
  1792. &Handle,
  1793. SYNCHRONIZE,
  1794. &Obja,
  1795. &IoStatusBlock,
  1796. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1797. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
  1798. );
  1799. if ( !NT_SUCCESS(Status) ) {
  1800. BaseSetLastNTError(Status);
  1801. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1802. //
  1803. // Prior releases of NT where these parameters were not optional
  1804. // zeroed out this field even in the failure case. Some applications
  1805. // failed to check the return value from this function and instead
  1806. // relied on this side effect. I'm putting that back now so the apps
  1807. // can still treat an unformatted volume as a zero size volume.
  1808. //
  1809. if (ARGUMENT_PRESENT( lpBytesPerSector )) {
  1810. *lpBytesPerSector = 0;
  1811. }
  1812. return FALSE;
  1813. }
  1814. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1815. //
  1816. // Determine the size parameters of the volume.
  1817. //
  1818. Status = NtQueryVolumeInformationFile(
  1819. Handle,
  1820. &IoStatusBlock,
  1821. &SizeInfo,
  1822. sizeof(SizeInfo),
  1823. FileFsSizeInformation
  1824. );
  1825. NtClose(Handle);
  1826. if ( !NT_SUCCESS(Status) ) {
  1827. BaseSetLastNTError(Status);
  1828. return FALSE;
  1829. }
  1830. //
  1831. // See if the calling process needs hack to work with HDD > 2GB
  1832. // 2GB is 0x80000000 bytes and some apps treat that as a signed LONG.
  1833. //
  1834. if (APPCOMPATFLAG(KACF_GETDISKFREESPACE)) {
  1835. bAppHack = TRUE;
  1836. } else {
  1837. bAppHack = FALSE;
  1838. }
  1839. //
  1840. // Deal with 64 bit sizes
  1841. //
  1842. if ( SizeInfo.TotalAllocationUnits.HighPart ) {
  1843. SizeInfo.TotalAllocationUnits.LowPart = (ULONG)-1;
  1844. }
  1845. if ( SizeInfo.AvailableAllocationUnits.HighPart ) {
  1846. SizeInfo.AvailableAllocationUnits.LowPart = (ULONG)-1;
  1847. }
  1848. if (ARGUMENT_PRESENT( lpSectorsPerCluster )) {
  1849. *lpSectorsPerCluster = SizeInfo.SectorsPerAllocationUnit;
  1850. }
  1851. if (ARGUMENT_PRESENT( lpBytesPerSector )) {
  1852. *lpBytesPerSector = SizeInfo.BytesPerSector;
  1853. }
  1854. if (ARGUMENT_PRESENT( lpNumberOfFreeClusters )) {
  1855. MAKE2GFRIENDLY(lpNumberOfFreeClusters, SizeInfo.AvailableAllocationUnits.LowPart);
  1856. }
  1857. if (ARGUMENT_PRESENT( lpTotalNumberOfClusters )) {
  1858. MAKE2GFRIENDLY(lpTotalNumberOfClusters, SizeInfo.TotalAllocationUnits.LowPart);
  1859. }
  1860. return TRUE;
  1861. }
  1862. WINBASEAPI
  1863. BOOL
  1864. WINAPI
  1865. GetDiskFreeSpaceExA(
  1866. LPCSTR lpDirectoryName,
  1867. PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  1868. PULARGE_INTEGER lpTotalNumberOfBytes,
  1869. PULARGE_INTEGER lpTotalNumberOfFreeBytes
  1870. )
  1871. {
  1872. PUNICODE_STRING Unicode;
  1873. if (!ARGUMENT_PRESENT( lpDirectoryName )) {
  1874. lpDirectoryName = "\\";
  1875. }
  1876. Unicode = Basep8BitStringToStaticUnicodeString( lpDirectoryName );
  1877. if (Unicode == NULL) {
  1878. return FALSE;
  1879. }
  1880. return ( GetDiskFreeSpaceExW(
  1881. (LPCWSTR)Unicode->Buffer,
  1882. lpFreeBytesAvailableToCaller,
  1883. lpTotalNumberOfBytes,
  1884. lpTotalNumberOfFreeBytes
  1885. )
  1886. );
  1887. }
  1888. WINBASEAPI
  1889. BOOL
  1890. WINAPI
  1891. GetDiskFreeSpaceExW(
  1892. LPCWSTR lpDirectoryName,
  1893. PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  1894. PULARGE_INTEGER lpTotalNumberOfBytes,
  1895. PULARGE_INTEGER lpTotalNumberOfFreeBytes
  1896. )
  1897. {
  1898. NTSTATUS Status;
  1899. OBJECT_ATTRIBUTES Obja;
  1900. HANDLE Handle;
  1901. UNICODE_STRING FileName;
  1902. IO_STATUS_BLOCK IoStatusBlock;
  1903. BOOLEAN TranslationStatus;
  1904. PVOID FreeBuffer;
  1905. union {
  1906. FILE_FS_SIZE_INFORMATION Normal;
  1907. FILE_FS_FULL_SIZE_INFORMATION Full;
  1908. } SizeInfo;
  1909. WCHAR DefaultPath[2];
  1910. ULARGE_INTEGER BytesPerAllocationUnit;
  1911. ULARGE_INTEGER FreeBytesAvailableToCaller;
  1912. ULARGE_INTEGER TotalNumberOfBytes;
  1913. DefaultPath[0] = (WCHAR)'\\';
  1914. DefaultPath[1] = UNICODE_NULL;
  1915. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1916. ARGUMENT_PRESENT(lpDirectoryName) ? lpDirectoryName : DefaultPath,
  1917. &FileName,
  1918. NULL,
  1919. NULL
  1920. );
  1921. if ( !TranslationStatus ) {
  1922. SetLastError(ERROR_PATH_NOT_FOUND);
  1923. return FALSE;
  1924. }
  1925. FreeBuffer = FileName.Buffer;
  1926. InitializeObjectAttributes(
  1927. &Obja,
  1928. &FileName,
  1929. OBJ_CASE_INSENSITIVE,
  1930. NULL,
  1931. NULL
  1932. );
  1933. //
  1934. // Open the file
  1935. //
  1936. Status = NtOpenFile(
  1937. &Handle,
  1938. SYNCHRONIZE,
  1939. &Obja,
  1940. &IoStatusBlock,
  1941. 0,
  1942. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
  1943. );
  1944. if ( !NT_SUCCESS(Status) ) {
  1945. BaseSetLastNTError(Status);
  1946. if ( GetLastError() == ERROR_FILE_NOT_FOUND ) {
  1947. SetLastError(ERROR_PATH_NOT_FOUND);
  1948. }
  1949. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1950. return FALSE;
  1951. }
  1952. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1953. //
  1954. // If the caller wants the volume total then try to get a full
  1955. // file size.
  1956. //
  1957. if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
  1958. Status = NtQueryVolumeInformationFile(
  1959. Handle,
  1960. &IoStatusBlock,
  1961. &SizeInfo,
  1962. sizeof(SizeInfo.Full),
  1963. FileFsFullSizeInformation
  1964. );
  1965. if ( NT_SUCCESS(Status) ) {
  1966. NtClose(Handle);
  1967. BytesPerAllocationUnit.QuadPart =
  1968. SizeInfo.Full.BytesPerSector * SizeInfo.Full.SectorsPerAllocationUnit;
  1969. if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
  1970. lpFreeBytesAvailableToCaller->QuadPart =
  1971. BytesPerAllocationUnit.QuadPart *
  1972. SizeInfo.Full.CallerAvailableAllocationUnits.QuadPart;
  1973. }
  1974. if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
  1975. lpTotalNumberOfBytes->QuadPart =
  1976. BytesPerAllocationUnit.QuadPart * SizeInfo.Full.TotalAllocationUnits.QuadPart;
  1977. }
  1978. lpTotalNumberOfFreeBytes->QuadPart =
  1979. BytesPerAllocationUnit.QuadPart *
  1980. SizeInfo.Full.ActualAvailableAllocationUnits.QuadPart;
  1981. return TRUE;
  1982. }
  1983. }
  1984. //
  1985. // Determine the size parameters of the volume.
  1986. //
  1987. Status = NtQueryVolumeInformationFile(
  1988. Handle,
  1989. &IoStatusBlock,
  1990. &SizeInfo,
  1991. sizeof(SizeInfo.Normal),
  1992. FileFsSizeInformation
  1993. );
  1994. NtClose(Handle);
  1995. if ( !NT_SUCCESS(Status) ) {
  1996. BaseSetLastNTError(Status);
  1997. return FALSE;
  1998. }
  1999. BytesPerAllocationUnit.QuadPart =
  2000. SizeInfo.Normal.BytesPerSector * SizeInfo.Normal.SectorsPerAllocationUnit;
  2001. FreeBytesAvailableToCaller.QuadPart =
  2002. BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.AvailableAllocationUnits.QuadPart;
  2003. TotalNumberOfBytes.QuadPart =
  2004. BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.TotalAllocationUnits.QuadPart;
  2005. if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
  2006. lpFreeBytesAvailableToCaller->QuadPart = FreeBytesAvailableToCaller.QuadPart;
  2007. }
  2008. if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
  2009. lpTotalNumberOfBytes->QuadPart = TotalNumberOfBytes.QuadPart;
  2010. }
  2011. if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
  2012. lpTotalNumberOfFreeBytes->QuadPart = FreeBytesAvailableToCaller.QuadPart;
  2013. }
  2014. return TRUE;
  2015. }
  2016. BOOL
  2017. APIENTRY
  2018. GetVolumeInformationA(
  2019. LPCSTR lpRootPathName,
  2020. LPSTR lpVolumeNameBuffer,
  2021. DWORD nVolumeNameSize,
  2022. LPDWORD lpVolumeSerialNumber,
  2023. LPDWORD lpMaximumComponentLength,
  2024. LPDWORD lpFileSystemFlags,
  2025. LPSTR lpFileSystemNameBuffer,
  2026. DWORD nFileSystemNameSize
  2027. )
  2028. /*++
  2029. Routine Description:
  2030. ANSI thunk to GetVolumeInformationW
  2031. --*/
  2032. {
  2033. PUNICODE_STRING Unicode;
  2034. NTSTATUS Status;
  2035. UNICODE_STRING UnicodeVolumeName;
  2036. UNICODE_STRING UnicodeFileSystemName;
  2037. ANSI_STRING AnsiVolumeName;
  2038. ANSI_STRING AnsiFileSystemName;
  2039. BOOL ReturnValue;
  2040. if (!ARGUMENT_PRESENT( lpRootPathName )) {
  2041. lpRootPathName = "\\";
  2042. }
  2043. Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
  2044. if (Unicode == NULL) {
  2045. return FALSE;
  2046. }
  2047. UnicodeVolumeName.Buffer = NULL;
  2048. UnicodeFileSystemName.Buffer = NULL;
  2049. UnicodeVolumeName.MaximumLength = 0;
  2050. UnicodeFileSystemName.MaximumLength = 0;
  2051. AnsiVolumeName.Buffer = lpVolumeNameBuffer;
  2052. AnsiVolumeName.MaximumLength = (USHORT)(nVolumeNameSize+1);
  2053. AnsiFileSystemName.Buffer = lpFileSystemNameBuffer;
  2054. AnsiFileSystemName.MaximumLength = (USHORT)(nFileSystemNameSize+1);
  2055. try {
  2056. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2057. UnicodeVolumeName.MaximumLength = AnsiVolumeName.MaximumLength << 1;
  2058. UnicodeVolumeName.Buffer = RtlAllocateHeap(
  2059. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2060. UnicodeVolumeName.MaximumLength
  2061. );
  2062. if ( !UnicodeVolumeName.Buffer ) {
  2063. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2064. ReturnValue = FALSE;
  2065. leave;
  2066. }
  2067. }
  2068. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2069. UnicodeFileSystemName.MaximumLength = AnsiFileSystemName.MaximumLength << 1;
  2070. UnicodeFileSystemName.Buffer = RtlAllocateHeap(
  2071. RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
  2072. UnicodeFileSystemName.MaximumLength
  2073. );
  2074. if ( !UnicodeFileSystemName.Buffer ) {
  2075. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2076. ReturnValue = FALSE;
  2077. leave;
  2078. }
  2079. }
  2080. ReturnValue = GetVolumeInformationW(
  2081. (LPCWSTR)Unicode->Buffer,
  2082. UnicodeVolumeName.Buffer,
  2083. nVolumeNameSize,
  2084. lpVolumeSerialNumber,
  2085. lpMaximumComponentLength,
  2086. lpFileSystemFlags,
  2087. UnicodeFileSystemName.Buffer,
  2088. nFileSystemNameSize
  2089. );
  2090. if ( ReturnValue ) {
  2091. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2092. RtlInitUnicodeString(
  2093. &UnicodeVolumeName,
  2094. UnicodeVolumeName.Buffer
  2095. );
  2096. Status = BasepUnicodeStringTo8BitString(
  2097. &AnsiVolumeName,
  2098. &UnicodeVolumeName,
  2099. FALSE
  2100. );
  2101. if ( !NT_SUCCESS(Status) ) {
  2102. BaseSetLastNTError(Status);
  2103. ReturnValue = FALSE;
  2104. leave;
  2105. }
  2106. }
  2107. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2108. RtlInitUnicodeString(
  2109. &UnicodeFileSystemName,
  2110. UnicodeFileSystemName.Buffer
  2111. );
  2112. Status = BasepUnicodeStringTo8BitString(
  2113. &AnsiFileSystemName,
  2114. &UnicodeFileSystemName,
  2115. FALSE
  2116. );
  2117. if ( !NT_SUCCESS(Status) ) {
  2118. BaseSetLastNTError(Status);
  2119. ReturnValue = FALSE;
  2120. leave;
  2121. }
  2122. }
  2123. }
  2124. }
  2125. finally {
  2126. if ( UnicodeVolumeName.Buffer ) {
  2127. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeVolumeName.Buffer);
  2128. }
  2129. if ( UnicodeFileSystemName.Buffer ) {
  2130. RtlFreeHeap(RtlProcessHeap(), 0,UnicodeFileSystemName.Buffer);
  2131. }
  2132. }
  2133. return ReturnValue;
  2134. }
  2135. BOOL
  2136. APIENTRY
  2137. GetVolumeInformationW(
  2138. LPCWSTR lpRootPathName,
  2139. LPWSTR lpVolumeNameBuffer,
  2140. DWORD nVolumeNameSize,
  2141. LPDWORD lpVolumeSerialNumber,
  2142. LPDWORD lpMaximumComponentLength,
  2143. LPDWORD lpFileSystemFlags,
  2144. LPWSTR lpFileSystemNameBuffer,
  2145. DWORD nFileSystemNameSize
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. This function returns information about the file system whose root
  2150. directory is specified.
  2151. Arguments:
  2152. lpRootPathName - An optional parameter, that if specified, supplies
  2153. the root directory of the file system that information is to be
  2154. returned about. If this parameter is not specified, then the
  2155. root of the current directory is used.
  2156. lpVolumeNameBuffer - An optional parameter that if specified returns
  2157. the name of the specified volume.
  2158. nVolumeNameSize - Supplies the length of the volume name buffer.
  2159. This parameter is ignored if the volume name buffer is not
  2160. supplied.
  2161. lpVolumeSerialNumber - An optional parameter that if specified
  2162. points to a DWORD. The DWORD contains the 32-bit of the volume
  2163. serial number.
  2164. lpMaximumComponentLength - An optional parameter that if specified
  2165. returns the maximum length of a filename component supported by
  2166. the specified file system. A filename component is that portion
  2167. of a filename between pathname seperators.
  2168. lpFileSystemFlags - An optional parameter that if specified returns
  2169. flags associated with the specified file system.
  2170. lpFileSystemFlags Flags:
  2171. FS_CASE_IS_PRESERVED - Indicates that the case of file names
  2172. is preserved when the name is placed on disk.
  2173. FS_CASE_SENSITIVE - Indicates that the file system supports
  2174. case sensitive file name lookup.
  2175. FS_UNICODE_STORED_ON_DISK - Indicates that the file system
  2176. supports unicode in file names as they appear on disk.
  2177. lpFileSystemNameBuffer - An optional parameter that if specified returns
  2178. the name for the specified file system (e.g. FAT, HPFS...).
  2179. nFileSystemNameSize - Supplies the length of the file system name
  2180. buffer. This parameter is ignored if the file system name
  2181. buffer is not supplied.
  2182. Return Value:
  2183. TRUE - The operation was successful.
  2184. FALSE/NULL - The operation failed. Extended error status is available
  2185. using GetLastError.
  2186. --*/
  2187. {
  2188. NTSTATUS Status;
  2189. OBJECT_ATTRIBUTES Obja;
  2190. HANDLE Handle;
  2191. UNICODE_STRING FileName;
  2192. IO_STATUS_BLOCK IoStatusBlock;
  2193. BOOLEAN TranslationStatus;
  2194. PVOID FreeBuffer;
  2195. PFILE_FS_ATTRIBUTE_INFORMATION AttributeInfo;
  2196. PFILE_FS_VOLUME_INFORMATION VolumeInfo;
  2197. ULONG AttributeInfoLength;
  2198. ULONG VolumeInfoLength;
  2199. WCHAR DefaultPath[2];
  2200. BOOL rv;
  2201. ULONG OriginalErrorMode;
  2202. rv = FALSE;
  2203. DefaultPath[0] = (WCHAR)'\\';
  2204. DefaultPath[1] = UNICODE_NULL;
  2205. nVolumeNameSize *= 2;
  2206. nFileSystemNameSize *= 2;
  2207. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2208. ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
  2209. &FileName,
  2210. NULL,
  2211. NULL
  2212. );
  2213. if ( !TranslationStatus ) {
  2214. SetLastError(ERROR_PATH_NOT_FOUND);
  2215. return FALSE;
  2216. }
  2217. FreeBuffer = FileName.Buffer;
  2218. //
  2219. // Check to make sure a root was specified
  2220. //
  2221. if ( FileName.Buffer[(FileName.Length >> 1)-1] != '\\' ) {
  2222. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2223. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  2224. return FALSE;
  2225. }
  2226. InitializeObjectAttributes(
  2227. &Obja,
  2228. &FileName,
  2229. OBJ_CASE_INSENSITIVE,
  2230. NULL,
  2231. NULL
  2232. );
  2233. AttributeInfo = NULL;
  2234. VolumeInfo = NULL;
  2235. //
  2236. // Open the file
  2237. //
  2238. RtlSetThreadErrorMode(RTL_ERRORMODE_FAILCRITICALERRORS,
  2239. &OriginalErrorMode);
  2240. Status = NtOpenFile(
  2241. &Handle,
  2242. SYNCHRONIZE,
  2243. &Obja,
  2244. &IoStatusBlock,
  2245. 0,
  2246. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  2247. );
  2248. RtlSetThreadErrorMode(OriginalErrorMode, NULL);
  2249. if ( !NT_SUCCESS(Status) ) {
  2250. BaseSetLastNTError(Status);
  2251. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2252. return FALSE;
  2253. }
  2254. if ( !IsThisARootDirectory(Handle,&FileName) ) {
  2255. NtClose(Handle);
  2256. SetLastError(ERROR_DIR_NOT_ROOT);
  2257. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2258. return FALSE;
  2259. }
  2260. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2261. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ||
  2262. ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
  2263. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2264. VolumeInfoLength = sizeof(*VolumeInfo)+nVolumeNameSize;
  2265. } else {
  2266. VolumeInfoLength = sizeof(*VolumeInfo)+MAX_PATH;
  2267. }
  2268. VolumeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), VolumeInfoLength);
  2269. if ( !VolumeInfo ) {
  2270. NtClose(Handle);
  2271. BaseSetLastNTError(STATUS_NO_MEMORY);
  2272. return FALSE;
  2273. }
  2274. }
  2275. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ||
  2276. ARGUMENT_PRESENT(lpMaximumComponentLength) ||
  2277. ARGUMENT_PRESENT(lpFileSystemFlags) ) {
  2278. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2279. AttributeInfoLength = sizeof(*AttributeInfo) + nFileSystemNameSize;
  2280. } else {
  2281. AttributeInfoLength = sizeof(*AttributeInfo) + MAX_PATH;
  2282. }
  2283. AttributeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AttributeInfoLength);
  2284. if ( !AttributeInfo ) {
  2285. NtClose(Handle);
  2286. if ( VolumeInfo ) {
  2287. RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
  2288. }
  2289. BaseSetLastNTError(STATUS_NO_MEMORY);
  2290. return FALSE;
  2291. }
  2292. }
  2293. try {
  2294. if ( VolumeInfo ) {
  2295. Status = NtQueryVolumeInformationFile(
  2296. Handle,
  2297. &IoStatusBlock,
  2298. VolumeInfo,
  2299. VolumeInfoLength,
  2300. FileFsVolumeInformation
  2301. );
  2302. if ( !NT_SUCCESS(Status) ) {
  2303. BaseSetLastNTError(Status);
  2304. rv = FALSE;
  2305. goto finally_exit;
  2306. }
  2307. }
  2308. if ( AttributeInfo ) {
  2309. Status = NtQueryVolumeInformationFile(
  2310. Handle,
  2311. &IoStatusBlock,
  2312. AttributeInfo,
  2313. AttributeInfoLength,
  2314. FileFsAttributeInformation
  2315. );
  2316. if ( !NT_SUCCESS(Status) ) {
  2317. BaseSetLastNTError(Status);
  2318. rv = FALSE;
  2319. goto finally_exit;
  2320. }
  2321. }
  2322. try {
  2323. if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
  2324. if ( VolumeInfo->VolumeLabelLength >= nVolumeNameSize ) {
  2325. SetLastError(ERROR_BAD_LENGTH);
  2326. rv = FALSE;
  2327. goto finally_exit;
  2328. } else {
  2329. RtlCopyMemory( lpVolumeNameBuffer,
  2330. VolumeInfo->VolumeLabel,
  2331. VolumeInfo->VolumeLabelLength );
  2332. *(lpVolumeNameBuffer + (VolumeInfo->VolumeLabelLength >> 1)) = UNICODE_NULL;
  2333. }
  2334. }
  2335. if ( ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
  2336. *lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
  2337. }
  2338. if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
  2339. if ( AttributeInfo->FileSystemNameLength >= nFileSystemNameSize ) {
  2340. SetLastError(ERROR_BAD_LENGTH);
  2341. rv = FALSE;
  2342. goto finally_exit;
  2343. } else {
  2344. RtlCopyMemory( lpFileSystemNameBuffer,
  2345. AttributeInfo->FileSystemName,
  2346. AttributeInfo->FileSystemNameLength );
  2347. *(lpFileSystemNameBuffer + (AttributeInfo->FileSystemNameLength >> 1)) = UNICODE_NULL;
  2348. }
  2349. }
  2350. if ( ARGUMENT_PRESENT(lpMaximumComponentLength) ) {
  2351. *lpMaximumComponentLength = AttributeInfo->MaximumComponentNameLength;
  2352. }
  2353. if ( ARGUMENT_PRESENT(lpFileSystemFlags) ) {
  2354. *lpFileSystemFlags = AttributeInfo->FileSystemAttributes;
  2355. }
  2356. } except (EXCEPTION_EXECUTE_HANDLER) {
  2357. BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
  2358. rv = FALSE;
  2359. goto finally_exit;
  2360. }
  2361. rv = TRUE;
  2362. finally_exit:;
  2363. } finally {
  2364. NtClose(Handle);
  2365. if ( VolumeInfo ) {
  2366. RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
  2367. }
  2368. if ( AttributeInfo ) {
  2369. RtlFreeHeap(RtlProcessHeap(), 0,AttributeInfo);
  2370. }
  2371. }
  2372. return rv;
  2373. }
  2374. DWORD
  2375. APIENTRY
  2376. GetLogicalDriveStringsA(
  2377. DWORD nBufferLength,
  2378. LPSTR lpBuffer
  2379. )
  2380. {
  2381. ULONG DriveMap;
  2382. ANSI_STRING RootName;
  2383. int i;
  2384. PUCHAR Dst;
  2385. DWORD BytesLeft;
  2386. DWORD BytesNeeded;
  2387. BOOL WeFailed;
  2388. CHAR szDrive[] = "A:\\";
  2389. BytesNeeded = 0;
  2390. BytesLeft = nBufferLength;
  2391. Dst = (PUCHAR)lpBuffer;
  2392. WeFailed = FALSE;
  2393. RtlInitAnsiString(&RootName, szDrive);
  2394. DriveMap = GetLogicalDrives();
  2395. for ( i=0; i<26; i++ ) {
  2396. RootName.Buffer[0] = (CHAR)((CHAR)i+'A');
  2397. if (DriveMap & (1 << i) ) {
  2398. BytesNeeded += RootName.MaximumLength;
  2399. if ( BytesNeeded < (USHORT)BytesLeft ) {
  2400. RtlCopyMemory(Dst,RootName.Buffer,RootName.MaximumLength);
  2401. Dst += RootName.MaximumLength;
  2402. *Dst = '\0';
  2403. } else {
  2404. WeFailed = TRUE;
  2405. }
  2406. }
  2407. }
  2408. if ( WeFailed ) {
  2409. BytesNeeded++;
  2410. }
  2411. //
  2412. // Need to handle network uses;
  2413. //
  2414. return( BytesNeeded );
  2415. }
  2416. DWORD
  2417. APIENTRY
  2418. GetLogicalDriveStringsW(
  2419. DWORD nBufferLength,
  2420. LPWSTR lpBuffer
  2421. )
  2422. {
  2423. ULONG DriveMap;
  2424. UNICODE_STRING RootName;
  2425. int i;
  2426. PUCHAR Dst;
  2427. DWORD BytesLeft;
  2428. DWORD BytesNeeded;
  2429. BOOL WeFailed;
  2430. WCHAR wszDrive[] = L"A:\\";
  2431. nBufferLength = nBufferLength*2;
  2432. BytesNeeded = 0;
  2433. BytesLeft = nBufferLength;
  2434. Dst = (PUCHAR)lpBuffer;
  2435. WeFailed = FALSE;
  2436. RtlInitUnicodeString(&RootName, wszDrive);
  2437. DriveMap = GetLogicalDrives();
  2438. for ( i=0; i<26; i++ ) {
  2439. RootName.Buffer[0] = (WCHAR)((CHAR)i+'A');
  2440. if (DriveMap & (1 << i) ) {
  2441. BytesNeeded += RootName.MaximumLength;
  2442. if ( BytesNeeded < (USHORT)BytesLeft ) {
  2443. RtlCopyMemory(Dst,RootName.Buffer,RootName.MaximumLength);
  2444. Dst += RootName.MaximumLength;
  2445. *(PWSTR)Dst = UNICODE_NULL;
  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