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

3866 lines
117 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. trcapi.c
  5. Abstract:
  6. This module contains implementations of win32 api's used in wmi files.
  7. Author:
  8. Revision History:
  9. --*/
  10. #include <nt.h>
  11. #include "wmiump.h"
  12. #include "trcapi.h"
  13. DWORD g_dwLastErrorToBreakOn = ERROR_SUCCESS;
  14. UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
  15. #define TLS_MASK 0x80000000
  16. #define TMP_TAG 0
  17. #define IsActiveConsoleSession() (USER_SHARED_DATA->ActiveConsoleId == NtCurrentPeb()->SessionId)
  18. #if defined(_WIN64) || defined(BUILD_WOW6432)
  19. SYSTEM_BASIC_INFORMATION SysInfo;
  20. #endif
  21. extern BOOLEAN CsrServerProcess;
  22. DWORD
  23. WmipGetLastError(
  24. VOID
  25. )
  26. /*++
  27. Routine Description:
  28. This function returns the most recent error code set by a Win32 API
  29. call. Applications should call this function immediately after a
  30. Win32 API call returns a failure indications (e.g. FALSE, NULL or
  31. -1) to determine the cause of the failure.
  32. The last error code value is a per thread field, so that multiple
  33. threads do not overwrite each other's last error code value.
  34. Arguments:
  35. None.
  36. Return Value:
  37. The return value is the most recent error code as set by a Win32 API
  38. call.
  39. --*/
  40. {
  41. return (DWORD)NtCurrentTeb()->LastErrorValue;
  42. }
  43. VOID
  44. WmipSetLastError(
  45. DWORD dwErrCode
  46. )
  47. /*++
  48. Routine Description:
  49. This function set the most recent error code and error string in per
  50. thread storage. Win32 API functions call this function whenever
  51. they return a failure indication (e.g. FALSE, NULL or -1).
  52. This function
  53. is not called by Win32 API function calls that are successful, so
  54. that if three Win32 API function calls are made, and the first one
  55. fails and the second two succeed, the error code and string stored
  56. by the first one are still available after the second two succeed.
  57. Applications can retrieve the values saved by this function using
  58. WmipGetLastError. The use of this function is optional, as an
  59. application need only call if it is interested in knowing the
  60. specific reason for an API function failure.
  61. The last error code value is kept in thread local storage so that
  62. multiple threads do not overwrite each other's values.
  63. Arguments:
  64. dwErrCode - Specifies the error code to store in per thread storage
  65. for the current thread.
  66. Return Value:
  67. return-value - Description of conditions needed to return value. - or -
  68. None.
  69. --*/
  70. {
  71. PTEB Teb = NtCurrentTeb();
  72. if ((g_dwLastErrorToBreakOn != ERROR_SUCCESS) &&
  73. (dwErrCode == g_dwLastErrorToBreakOn)) {
  74. DbgBreakPoint();
  75. }
  76. // make write breakpoints to this field more meaningful by only writing to it when
  77. // the value changes.
  78. if (Teb->LastErrorValue != dwErrCode) {
  79. Teb->LastErrorValue = dwErrCode;
  80. }
  81. }
  82. DWORD
  83. WINAPI
  84. WmipGetTimeZoneInformation(
  85. LPTIME_ZONE_INFORMATION lpTimeZoneInformation
  86. )
  87. /*++
  88. Routine Description:
  89. This function allows an application to get the current timezone
  90. parameters These parameters control the Universal time to Local time
  91. translations.
  92. All UTC time to Local time translations are based on the following
  93. formula:
  94. UTC = LocalTime + Bias
  95. The return value of this function is the systems best guess of
  96. the current time zone parameters. This is one of:
  97. - Unknown
  98. - Standard Time
  99. - Daylight Savings Time
  100. If SetTimeZoneInformation was called without the transition date
  101. information, Unknown is returned, but the currect bias is used for
  102. local time translation. Otherwise, the system will correctly pick
  103. either daylight savings time or standard time.
  104. The information returned by this API is identical to the information
  105. stored in the last successful call to SetTimeZoneInformation. The
  106. exception is the Bias field returns the current Bias value in
  107. Arguments:
  108. lpTimeZoneInformation - Supplies the address of the time zone
  109. information structure.
  110. Return Value:
  111. TIME_ZONE_ID_UNKNOWN - The system can not determine the current
  112. timezone. This is usually due to a previous call to
  113. SetTimeZoneInformation where only the Bias was supplied and no
  114. transition dates were supplied.
  115. TIME_ZONE_ID_STANDARD - The system is operating in the range covered
  116. by StandardDate.
  117. TIME_ZONE_ID_DAYLIGHT - The system is operating in the range covered
  118. by DaylightDate.
  119. 0xffffffff - The operation failed. Extended error status is
  120. available using WmipGetLastError.
  121. --*/
  122. {
  123. RTL_TIME_ZONE_INFORMATION tzi;
  124. NTSTATUS Status;
  125. //
  126. // get the timezone data from the system
  127. // If it's terminal server session use client time zone
  128. Status = NtQuerySystemInformation(
  129. SystemCurrentTimeZoneInformation,
  130. &tzi,
  131. sizeof(tzi),
  132. NULL
  133. );
  134. if ( !NT_SUCCESS(Status) ) {
  135. WmipBaseSetLastNTError(Status);
  136. return 0xffffffff;
  137. }
  138. lpTimeZoneInformation->Bias = tzi.Bias;
  139. lpTimeZoneInformation->StandardBias = tzi.StandardBias;
  140. lpTimeZoneInformation->DaylightBias = tzi.DaylightBias;
  141. RtlMoveMemory(&lpTimeZoneInformation->StandardName,&tzi.StandardName,sizeof(tzi.StandardName));
  142. RtlMoveMemory(&lpTimeZoneInformation->DaylightName,&tzi.DaylightName,sizeof(tzi.DaylightName));
  143. lpTimeZoneInformation->StandardDate.wYear = tzi.StandardStart.Year ;
  144. lpTimeZoneInformation->StandardDate.wMonth = tzi.StandardStart.Month ;
  145. lpTimeZoneInformation->StandardDate.wDayOfWeek = tzi.StandardStart.Weekday ;
  146. lpTimeZoneInformation->StandardDate.wDay = tzi.StandardStart.Day ;
  147. lpTimeZoneInformation->StandardDate.wHour = tzi.StandardStart.Hour ;
  148. lpTimeZoneInformation->StandardDate.wMinute = tzi.StandardStart.Minute ;
  149. lpTimeZoneInformation->StandardDate.wSecond = tzi.StandardStart.Second ;
  150. lpTimeZoneInformation->StandardDate.wMilliseconds = tzi.StandardStart.Milliseconds;
  151. lpTimeZoneInformation->DaylightDate.wYear = tzi.DaylightStart.Year ;
  152. lpTimeZoneInformation->DaylightDate.wMonth = tzi.DaylightStart.Month ;
  153. lpTimeZoneInformation->DaylightDate.wDayOfWeek = tzi.DaylightStart.Weekday ;
  154. lpTimeZoneInformation->DaylightDate.wDay = tzi.DaylightStart.Day ;
  155. lpTimeZoneInformation->DaylightDate.wHour = tzi.DaylightStart.Hour ;
  156. lpTimeZoneInformation->DaylightDate.wMinute = tzi.DaylightStart.Minute ;
  157. lpTimeZoneInformation->DaylightDate.wSecond = tzi.DaylightStart.Second ;
  158. lpTimeZoneInformation->DaylightDate.wMilliseconds = tzi.DaylightStart.Milliseconds;
  159. return USER_SHARED_DATA->TimeZoneId;
  160. }
  161. BOOL
  162. WINAPI
  163. WmipGetVersionExW(
  164. LPOSVERSIONINFOW lpVersionInformation
  165. )
  166. {
  167. PPEB Peb;
  168. NTSTATUS Status;
  169. if (lpVersionInformation->dwOSVersionInfoSize != sizeof( OSVERSIONINFOEXW ) &&
  170. lpVersionInformation->dwOSVersionInfoSize != sizeof( *lpVersionInformation )
  171. ) {
  172. WmipSetLastError( ERROR_INSUFFICIENT_BUFFER );
  173. return FALSE;
  174. }
  175. Status = RtlGetVersion(lpVersionInformation);
  176. if (Status == STATUS_SUCCESS) {
  177. Peb = NtCurrentPeb();
  178. if (Peb->CSDVersion.Buffer)
  179. wcscpy( lpVersionInformation->szCSDVersion, Peb->CSDVersion.Buffer );
  180. if (lpVersionInformation->dwOSVersionInfoSize ==
  181. sizeof( OSVERSIONINFOEXW))
  182. ((POSVERSIONINFOEXW)lpVersionInformation)->wReserved =
  183. (UCHAR)BaseRCNumber;
  184. return TRUE;
  185. } else {
  186. return FALSE;
  187. }
  188. }
  189. BOOL
  190. WINAPI
  191. WmipGetVersionExA(
  192. LPOSVERSIONINFOA lpVersionInformation
  193. )
  194. {
  195. OSVERSIONINFOEXW VersionInformationU;
  196. ANSI_STRING AnsiString;
  197. UNICODE_STRING UnicodeString;
  198. NTSTATUS Status;
  199. if (lpVersionInformation->dwOSVersionInfoSize != sizeof( OSVERSIONINFOEXA ) &&
  200. lpVersionInformation->dwOSVersionInfoSize != sizeof( *lpVersionInformation )
  201. ) {
  202. WmipSetLastError( ERROR_INSUFFICIENT_BUFFER );
  203. return FALSE;
  204. }
  205. VersionInformationU.dwOSVersionInfoSize = sizeof( VersionInformationU );
  206. if (WmipGetVersionExW( (LPOSVERSIONINFOW)&VersionInformationU )) {
  207. lpVersionInformation->dwMajorVersion = VersionInformationU.dwMajorVersion;
  208. lpVersionInformation->dwMinorVersion = VersionInformationU.dwMinorVersion;
  209. lpVersionInformation->dwBuildNumber = VersionInformationU.dwBuildNumber;
  210. lpVersionInformation->dwPlatformId = VersionInformationU.dwPlatformId;
  211. if (lpVersionInformation->dwOSVersionInfoSize == sizeof( OSVERSIONINFOEXA )) {
  212. ((POSVERSIONINFOEXA)lpVersionInformation)->wServicePackMajor = VersionInformationU.wServicePackMajor;
  213. ((POSVERSIONINFOEXA)lpVersionInformation)->wServicePackMinor = VersionInformationU.wServicePackMinor;
  214. ((POSVERSIONINFOEXA)lpVersionInformation)->wSuiteMask = VersionInformationU.wSuiteMask;
  215. ((POSVERSIONINFOEXA)lpVersionInformation)->wProductType = VersionInformationU.wProductType;
  216. ((POSVERSIONINFOEXA)lpVersionInformation)->wReserved = VersionInformationU.wReserved;
  217. }
  218. AnsiString.Buffer = lpVersionInformation->szCSDVersion;
  219. AnsiString.Length = 0;
  220. AnsiString.MaximumLength = sizeof( lpVersionInformation->szCSDVersion );
  221. RtlInitUnicodeString( &UnicodeString, VersionInformationU.szCSDVersion );
  222. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  223. &UnicodeString,
  224. FALSE
  225. );
  226. if (NT_SUCCESS( Status )) {
  227. return TRUE;
  228. }
  229. else {
  230. return FALSE;
  231. }
  232. }
  233. else {
  234. return FALSE;
  235. }
  236. }
  237. ULONG
  238. WmipBaseSetLastNTError(
  239. IN NTSTATUS Status
  240. )
  241. /*++
  242. Routine Description:
  243. This API sets the "last error value" and the "last error string"
  244. based on the value of Status. For status codes that don't have
  245. a corresponding error string, the string is set to null.
  246. Arguments:
  247. Status - Supplies the status value to store as the last error value.
  248. Return Value:
  249. The corresponding Win32 error code that was stored in the
  250. "last error value" thread variable.
  251. --*/
  252. {
  253. ULONG dwErrorCode;
  254. dwErrorCode = RtlNtStatusToDosError( Status );
  255. WmipSetLastError( dwErrorCode );
  256. return( dwErrorCode );
  257. }
  258. PUNICODE_STRING
  259. WmipBasep8BitStringToStaticUnicodeString(
  260. IN LPCSTR lpSourceString
  261. )
  262. /*++
  263. Routine Description:
  264. Captures and converts a 8-bit (OEM or ANSI) string into the Teb Static
  265. Unicode String
  266. Arguments:
  267. lpSourceString - string in OEM or ANSI
  268. Return Value:
  269. Pointer to the Teb static string if conversion was successful, NULL
  270. otherwise. If a failure occurred, the last error is set.
  271. --*/
  272. {
  273. PUNICODE_STRING StaticUnicode;
  274. ANSI_STRING AnsiString;
  275. NTSTATUS Status;
  276. //
  277. // Get pointer to static per-thread string
  278. //
  279. StaticUnicode = &NtCurrentTeb()->StaticUnicodeString;
  280. //
  281. // Convert input string into unicode string
  282. //
  283. RtlInitAnsiString( &AnsiString, lpSourceString );
  284. //Status = Basep8BitStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
  285. Status = RtlAnsiStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
  286. //
  287. // If we couldn't convert the string
  288. //
  289. if ( !NT_SUCCESS( Status ) ) {
  290. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  291. WmipSetLastError( ERROR_FILENAME_EXCED_RANGE );
  292. } else {
  293. WmipBaseSetLastNTError( Status );
  294. }
  295. return NULL;
  296. } else {
  297. return StaticUnicode;
  298. }
  299. }
  300. HANDLE
  301. WINAPI
  302. WmipCreateFileW(
  303. LPCWSTR lpFileName,
  304. DWORD dwDesiredAccess,
  305. DWORD dwShareMode,
  306. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  307. DWORD dwCreationDisposition,
  308. DWORD dwFlagsAndAttributes,
  309. HANDLE hTemplateFile
  310. )
  311. /*++
  312. Routine Description:
  313. A file can be created, opened, or truncated, and a handle opened to
  314. access the new file using CreateFile.
  315. This API is used to create or open a file and obtain a handle to it
  316. that allows reading data, writing data, and moving the file pointer.
  317. This API allows the caller to specify the following creation
  318. dispositions:
  319. - Create a new file and fail if the file exists ( CREATE_NEW )
  320. - Create a new file and succeed if it exists ( CREATE_ALWAYS )
  321. - Open an existing file ( OPEN_EXISTING )
  322. - Open and existing file or create it if it does not exist (
  323. OPEN_ALWAYS )
  324. - Truncate and existing file ( TRUNCATE_EXISTING )
  325. If this call is successful, a handle is returned that has
  326. appropriate access to the specified file.
  327. If as a result of this call, a file is created,
  328. - The attributes of the file are determined by the value of the
  329. FileAttributes parameter or'd with the FILE_ATTRIBUTE_ARCHIVE bit.
  330. - The length of the file will be set to zero.
  331. - If the hTemplateFile parameter is specified, any extended
  332. attributes associated with the file are assigned to the new file.
  333. If a new file is not created, then the hTemplateFile is ignored as
  334. are any extended attributes.
  335. For DOS based systems running share.exe the file sharing semantics
  336. work as described above. Without share.exe no share level
  337. protection exists.
  338. This call is logically equivalent to DOS (int 21h, function 5Bh), or
  339. DOS (int 21h, function 3Ch) depending on the value of the
  340. FailIfExists parameter.
  341. Arguments:
  342. lpFileName - Supplies the file name of the file to open. Depending on
  343. the value of the FailIfExists parameter, this name may or may
  344. not already exist.
  345. dwDesiredAccess - Supplies the caller's desired access to the file.
  346. DesiredAccess Flags:
  347. GENERIC_READ - Read access to the file is requested. This
  348. allows data to be read from the file and the file pointer to
  349. be modified.
  350. GENERIC_WRITE - Write access to the file is requested. This
  351. allows data to be written to the file and the file pointer to
  352. be modified.
  353. dwShareMode - Supplies a set of flags that indicates how this file is
  354. to be shared with other openers of the file. A value of zero
  355. for this parameter indicates no sharing of the file, or
  356. exclusive access to the file is to occur.
  357. ShareMode Flags:
  358. FILE_SHARE_READ - Other open operations may be performed on the
  359. file for read access.
  360. FILE_SHARE_WRITE - Other open operations may be performed on the
  361. file for write access.
  362. lpSecurityAttributes - An optional parameter that, if present, and
  363. supported on the target file system supplies a security
  364. descriptor for the new file.
  365. dwCreationDisposition - Supplies a creation disposition that
  366. specifies how this call is to operate. This parameter must be
  367. one of the following values.
  368. dwCreationDisposition Value:
  369. CREATE_NEW - Create a new file. If the specified file already
  370. exists, then fail. The attributes for the new file are what
  371. is specified in the dwFlagsAndAttributes parameter or'd with
  372. FILE_ATTRIBUTE_ARCHIVE. If the hTemplateFile is specified,
  373. then any extended attributes associated with that file are
  374. propogated to the new file.
  375. CREATE_ALWAYS - Always create the file. If the file already
  376. exists, then it is overwritten. The attributes for the new
  377. file are what is specified in the dwFlagsAndAttributes
  378. parameter or'd with FILE_ATTRIBUTE_ARCHIVE. If the
  379. hTemplateFile is specified, then any extended attributes
  380. associated with that file are propogated to the new file.
  381. OPEN_EXISTING - Open the file, but if it does not exist, then
  382. fail the call.
  383. OPEN_ALWAYS - Open the file if it exists. If it does not exist,
  384. then create the file using the same rules as if the
  385. disposition were CREATE_NEW.
  386. TRUNCATE_EXISTING - Open the file, but if it does not exist,
  387. then fail the call. Once opened, the file is truncated such
  388. that its size is zero bytes. This disposition requires that
  389. the caller open the file with at least GENERIC_WRITE access.
  390. dwFlagsAndAttributes - Specifies flags and attributes for the file.
  391. The attributes are only used when the file is created (as
  392. opposed to opened or truncated). Any combination of attribute
  393. flags is acceptable except that all other attribute flags
  394. override the normal file attribute, FILE_ATTRIBUTE_NORMAL. The
  395. FILE_ATTRIBUTE_ARCHIVE flag is always implied.
  396. dwFlagsAndAttributes Flags:
  397. FILE_ATTRIBUTE_NORMAL - A normal file should be created.
  398. FILE_ATTRIBUTE_READONLY - A read-only file should be created.
  399. FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
  400. FILE_ATTRIBUTE_SYSTEM - A system file should be created.
  401. FILE_FLAG_WRITE_THROUGH - Indicates that the system should
  402. always write through any intermediate cache and go directly
  403. to the file. The system may still cache writes, but may not
  404. lazily flush the writes.
  405. FILE_FLAG_OVERLAPPED - Indicates that the system should initialize
  406. the file so that ReadFile and WriteFile operations that may
  407. take a significant time to complete will return ERROR_IO_PENDING.
  408. An event will be set to the signalled state when the operation
  409. completes. When FILE_FLAG_OVERLAPPED is specified the system will
  410. not maintain the file pointer. The position to read/write from
  411. is passed to the system as part of the OVERLAPPED structure
  412. which is an optional parameter to ReadFile and WriteFile.
  413. FILE_FLAG_NO_BUFFERING - Indicates that the file is to be opened
  414. with no intermediate buffering or caching done by the
  415. system. Reads and writes to the file must be done on sector
  416. boundries. Buffer addresses for reads and writes must be
  417. aligned on at least disk sector boundries in memory.
  418. FILE_FLAG_RANDOM_ACCESS - Indicates that access to the file may
  419. be random. The system cache manager may use this to influence
  420. its caching strategy for this file.
  421. FILE_FLAG_SEQUENTIAL_SCAN - Indicates that access to the file
  422. may be sequential. The system cache manager may use this to
  423. influence its caching strategy for this file. The file may
  424. in fact be accessed randomly, but the cache manager may
  425. optimize its cacheing policy for sequential access.
  426. FILE_FLAG_DELETE_ON_CLOSE - Indicates that the file is to be
  427. automatically deleted when the last handle to it is closed.
  428. FILE_FLAG_BACKUP_SEMANTICS - Indicates that the file is being opened
  429. or created for the purposes of either a backup or a restore
  430. operation. Thus, the system should make whatever checks are
  431. appropriate to ensure that the caller is able to override
  432. whatever security checks have been placed on the file to allow
  433. this to happen.
  434. FILE_FLAG_POSIX_SEMANTICS - Indicates that the file being opened
  435. should be accessed in a manner compatible with the rules used
  436. by POSIX. This includes allowing multiple files with the same
  437. name, differing only in case. WARNING: Use of this flag may
  438. render it impossible for a DOS, WIN-16, or WIN-32 application
  439. to access the file.
  440. FILE_FLAG_OPEN_REPARSE_POINT - Indicates that the file being opened
  441. should be accessed as if it were a reparse point. WARNING: Use
  442. of this flag may inhibit the operation of file system filter drivers
  443. present in the I/O subsystem.
  444. FILE_FLAG_OPEN_NO_RECALL - Indicates that all the state of the file
  445. should be acessed without changing its storage location. Thus,
  446. in the case of files that have parts of its state stored at a
  447. remote servicer, no permanent recall of data is to happen.
  448. Security Quality of Service information may also be specified in
  449. the dwFlagsAndAttributes parameter. These bits are meaningful
  450. only if the file being opened is the client side of a Named
  451. Pipe. Otherwise they are ignored.
  452. SECURITY_SQOS_PRESENT - Indicates that the Security Quality of
  453. Service bits contain valid values.
  454. Impersonation Levels:
  455. SECURITY_ANONYMOUS - Specifies that the client should be impersonated
  456. at Anonymous impersonation level.
  457. SECURITY_IDENTIFICAION - Specifies that the client should be impersonated
  458. at Identification impersonation level.
  459. SECURITY_IMPERSONATION - Specifies that the client should be impersonated
  460. at Impersonation impersonation level.
  461. SECURITY_DELEGATION - Specifies that the client should be impersonated
  462. at Delegation impersonation level.
  463. Context Tracking:
  464. SECURITY_CONTEXT_TRACKING - A boolean flag that when set,
  465. specifies that the Security Tracking Mode should be
  466. Dynamic, otherwise Static.
  467. SECURITY_EFFECTIVE_ONLY - A boolean flag indicating whether
  468. the entire security context of the client is to be made
  469. available to the server or only the effective aspects of
  470. the context.
  471. hTemplateFile - An optional parameter, then if specified, supplies a
  472. handle with GENERIC_READ access to a template file. The
  473. template file is used to supply extended attributes for the file
  474. being created. When the new file is created, the relevant attributes
  475. from the template file are used in creating the new file.
  476. Return Value:
  477. Not -1 - Returns an open handle to the specified file. Subsequent
  478. access to the file is controlled by the DesiredAccess parameter.
  479. 0xffffffff - The operation failed. Extended error status is available
  480. using WmipGetLastError.
  481. --*/
  482. {
  483. NTSTATUS Status;
  484. OBJECT_ATTRIBUTES Obja;
  485. HANDLE Handle;
  486. UNICODE_STRING FileName;
  487. IO_STATUS_BLOCK IoStatusBlock;
  488. BOOLEAN TranslationStatus;
  489. RTL_RELATIVE_NAME RelativeName;
  490. PVOID FreeBuffer;
  491. ULONG CreateDisposition;
  492. ULONG CreateFlags;
  493. FILE_ALLOCATION_INFORMATION AllocationInfo;
  494. FILE_EA_INFORMATION EaInfo;
  495. PFILE_FULL_EA_INFORMATION EaBuffer;
  496. ULONG EaSize;
  497. PUNICODE_STRING lpConsoleName;
  498. BOOL bInheritHandle;
  499. BOOL EndsInSlash;
  500. DWORD SQOSFlags;
  501. BOOLEAN ContextTrackingMode = FALSE;
  502. BOOLEAN EffectiveOnly = FALSE;
  503. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = 0;
  504. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  505. switch ( dwCreationDisposition ) {
  506. case CREATE_NEW :
  507. CreateDisposition = FILE_CREATE;
  508. break;
  509. case CREATE_ALWAYS :
  510. CreateDisposition = FILE_OVERWRITE_IF;
  511. break;
  512. case OPEN_EXISTING :
  513. CreateDisposition = FILE_OPEN;
  514. break;
  515. case OPEN_ALWAYS :
  516. CreateDisposition = FILE_OPEN_IF;
  517. break;
  518. case TRUNCATE_EXISTING :
  519. CreateDisposition = FILE_OPEN;
  520. if ( !(dwDesiredAccess & GENERIC_WRITE) ) {
  521. WmipBaseSetLastNTError(STATUS_INVALID_PARAMETER);
  522. return INVALID_HANDLE_VALUE;
  523. }
  524. break;
  525. default :
  526. WmipBaseSetLastNTError(STATUS_INVALID_PARAMETER);
  527. return INVALID_HANDLE_VALUE;
  528. }
  529. // temporary routing code
  530. RtlInitUnicodeString(&FileName,lpFileName);
  531. if ( FileName.Length > 1 && lpFileName[(FileName.Length >> 1)-1] == (WCHAR)'\\' ) {
  532. EndsInSlash = TRUE;
  533. }
  534. else {
  535. EndsInSlash = FALSE;
  536. }
  537. /*
  538. if ((lpConsoleName = WmipBaseIsThisAConsoleName(&FileName,dwDesiredAccess)) ) {
  539. Handle = INVALID_HANDLE_VALUE;
  540. bInheritHandle = FALSE;
  541. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  542. bInheritHandle = lpSecurityAttributes->bInheritHandle;
  543. }
  544. Handle = WmipOpenConsoleW(lpConsoleName,
  545. dwDesiredAccess,
  546. bInheritHandle,
  547. FILE_SHARE_READ | FILE_SHARE_WRITE //dwShareMode
  548. );
  549. if ( Handle == INVALID_HANDLE_VALUE ) {
  550. WmipBaseSetLastNTError(STATUS_ACCESS_DENIED);
  551. return INVALID_HANDLE_VALUE;
  552. }
  553. else {
  554. WmipSetLastError(0);
  555. return Handle;
  556. }
  557. }*/
  558. // end temporary code
  559. CreateFlags = 0;
  560. TranslationStatus = RtlDosPathNameToNtPathName_U(
  561. lpFileName,
  562. &FileName,
  563. NULL,
  564. &RelativeName
  565. );
  566. if ( !TranslationStatus ) {
  567. WmipSetLastError(ERROR_PATH_NOT_FOUND);
  568. return INVALID_HANDLE_VALUE;
  569. }
  570. FreeBuffer = FileName.Buffer;
  571. if ( RelativeName.RelativeName.Length ) {
  572. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  573. }
  574. else {
  575. RelativeName.ContainingDirectory = NULL;
  576. }
  577. InitializeObjectAttributes(
  578. &Obja,
  579. &FileName,
  580. dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ? 0 : OBJ_CASE_INSENSITIVE,
  581. RelativeName.ContainingDirectory,
  582. NULL
  583. );
  584. SQOSFlags = dwFlagsAndAttributes & SECURITY_VALID_SQOS_FLAGS;
  585. if ( SQOSFlags & SECURITY_SQOS_PRESENT ) {
  586. SQOSFlags &= ~SECURITY_SQOS_PRESENT;
  587. if (SQOSFlags & SECURITY_CONTEXT_TRACKING) {
  588. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) TRUE;
  589. SQOSFlags &= ~SECURITY_CONTEXT_TRACKING;
  590. } else {
  591. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) FALSE;
  592. }
  593. if (SQOSFlags & SECURITY_EFFECTIVE_ONLY) {
  594. SecurityQualityOfService.EffectiveOnly = TRUE;
  595. SQOSFlags &= ~SECURITY_EFFECTIVE_ONLY;
  596. } else {
  597. SecurityQualityOfService.EffectiveOnly = FALSE;
  598. }
  599. SecurityQualityOfService.ImpersonationLevel = SQOSFlags >> 16;
  600. } else {
  601. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  602. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  603. SecurityQualityOfService.EffectiveOnly = TRUE;
  604. }
  605. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  606. Obja.SecurityQualityOfService = &SecurityQualityOfService;
  607. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  608. Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  609. if ( lpSecurityAttributes->bInheritHandle ) {
  610. Obja.Attributes |= OBJ_INHERIT;
  611. }
  612. }
  613. EaBuffer = NULL;
  614. EaSize = 0;
  615. if ( ARGUMENT_PRESENT(hTemplateFile) ) {
  616. Status = NtQueryInformationFile(
  617. hTemplateFile,
  618. &IoStatusBlock,
  619. &EaInfo,
  620. sizeof(EaInfo),
  621. FileEaInformation
  622. );
  623. if ( NT_SUCCESS(Status) && EaInfo.EaSize ) {
  624. EaSize = EaInfo.EaSize;
  625. do {
  626. EaSize *= 2;
  627. EaBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), EaSize);
  628. if ( !EaBuffer ) {
  629. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  630. WmipBaseSetLastNTError(STATUS_NO_MEMORY);
  631. return INVALID_HANDLE_VALUE;
  632. }
  633. Status = NtQueryEaFile(
  634. hTemplateFile,
  635. &IoStatusBlock,
  636. EaBuffer,
  637. EaSize,
  638. FALSE,
  639. (PVOID)NULL,
  640. 0,
  641. (PULONG)NULL,
  642. TRUE
  643. );
  644. if ( !NT_SUCCESS(Status) ) {
  645. RtlFreeHeap(RtlProcessHeap(), 0,EaBuffer);
  646. EaBuffer = NULL;
  647. IoStatusBlock.Information = 0;
  648. }
  649. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  650. Status == STATUS_BUFFER_TOO_SMALL );
  651. EaSize = (ULONG)IoStatusBlock.Information;
  652. }
  653. }
  654. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
  655. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
  656. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
  657. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
  658. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
  659. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
  660. if ( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE ) {
  661. CreateFlags |= FILE_DELETE_ON_CLOSE;
  662. dwDesiredAccess |= DELETE;
  663. }
  664. if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT ) {
  665. CreateFlags |= FILE_OPEN_REPARSE_POINT;
  666. }
  667. if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL ) {
  668. CreateFlags |= FILE_OPEN_NO_RECALL;
  669. }
  670. //
  671. // Backup semantics allow directories to be opened
  672. //
  673. if ( !(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) ) {
  674. CreateFlags |= FILE_NON_DIRECTORY_FILE;
  675. }
  676. else {
  677. //
  678. // Backup intent was specified... Now look to see if we are to allow
  679. // directory creation
  680. //
  681. if ( (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
  682. (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ) &&
  683. (CreateDisposition == FILE_CREATE) ) {
  684. CreateFlags |= FILE_DIRECTORY_FILE;
  685. }
  686. }
  687. Status = NtCreateFile(
  688. &Handle,
  689. (ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  690. &Obja,
  691. &IoStatusBlock,
  692. NULL,
  693. dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY),
  694. dwShareMode,
  695. CreateDisposition,
  696. CreateFlags,
  697. EaBuffer,
  698. EaSize
  699. );
  700. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  701. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
  702. if ( !NT_SUCCESS(Status) ) {
  703. WmipBaseSetLastNTError(Status);
  704. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  705. WmipSetLastError(ERROR_FILE_EXISTS);
  706. }
  707. else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
  708. if ( EndsInSlash ) {
  709. WmipSetLastError(ERROR_PATH_NOT_FOUND);
  710. }
  711. else {
  712. WmipSetLastError(ERROR_ACCESS_DENIED);
  713. }
  714. }
  715. return INVALID_HANDLE_VALUE;
  716. }
  717. //
  718. // if NT returns supersede/overwritten, it means that a create_always, openalways
  719. // found an existing copy of the file. In this case ERROR_ALREADY_EXISTS is returned
  720. //
  721. if ( (dwCreationDisposition == CREATE_ALWAYS && IoStatusBlock.Information == FILE_OVERWRITTEN) ||
  722. (dwCreationDisposition == OPEN_ALWAYS && IoStatusBlock.Information == FILE_OPENED) ){
  723. WmipSetLastError(ERROR_ALREADY_EXISTS);
  724. }
  725. else {
  726. WmipSetLastError(0);
  727. }
  728. //
  729. // Truncate the file if required
  730. //
  731. if ( dwCreationDisposition == TRUNCATE_EXISTING) {
  732. AllocationInfo.AllocationSize.QuadPart = 0;
  733. Status = NtSetInformationFile(
  734. Handle,
  735. &IoStatusBlock,
  736. &AllocationInfo,
  737. sizeof(AllocationInfo),
  738. FileAllocationInformation
  739. );
  740. if ( !NT_SUCCESS(Status) ) {
  741. WmipBaseSetLastNTError(Status);
  742. NtClose(Handle);
  743. Handle = INVALID_HANDLE_VALUE;
  744. }
  745. }
  746. //
  747. // Deal with hTemplateFile
  748. //
  749. return Handle;
  750. }
  751. HANDLE
  752. WmipBaseGetNamedObjectDirectory(
  753. VOID
  754. )
  755. {
  756. OBJECT_ATTRIBUTES Obja;
  757. NTSTATUS Status;
  758. UNICODE_STRING RestrictedObjectDirectory;
  759. ACCESS_MASK DirAccess = DIRECTORY_ALL_ACCESS &
  760. ~(DELETE | WRITE_DAC | WRITE_OWNER);
  761. HANDLE hRootNamedObject;
  762. HANDLE BaseHandle;
  763. if ( BaseNamedObjectDirectory != NULL) {
  764. return BaseNamedObjectDirectory;
  765. }
  766. RtlAcquirePebLock();
  767. if ( !BaseNamedObjectDirectory ) {
  768. BASE_READ_REMOTE_STR_TEMP(TempStr);
  769. InitializeObjectAttributes( &Obja,
  770. BASE_READ_REMOTE_STR(BaseStaticServerData->NamedObjectDirectory, TempStr),
  771. OBJ_CASE_INSENSITIVE,
  772. NULL,
  773. NULL
  774. );
  775. Status = NtOpenDirectoryObject( &BaseHandle,
  776. DirAccess,
  777. &Obja
  778. );
  779. // if the intial open failed, try again with just traverse, and
  780. // open the restricted subdirectory
  781. if ( !NT_SUCCESS(Status) ) {
  782. Status = NtOpenDirectoryObject( &hRootNamedObject,
  783. DIRECTORY_TRAVERSE,
  784. &Obja
  785. );
  786. if ( NT_SUCCESS(Status) ) {
  787. RtlInitUnicodeString( &RestrictedObjectDirectory, L"Restricted");
  788. InitializeObjectAttributes( &Obja,
  789. &RestrictedObjectDirectory,
  790. OBJ_CASE_INSENSITIVE,
  791. hRootNamedObject,
  792. NULL
  793. );
  794. Status = NtOpenDirectoryObject( &BaseHandle,
  795. DirAccess,
  796. &Obja
  797. );
  798. NtClose( hRootNamedObject );
  799. }
  800. }
  801. if ( NT_SUCCESS(Status) ) {
  802. BaseNamedObjectDirectory = BaseHandle;
  803. }
  804. }
  805. RtlReleasePebLock();
  806. return BaseNamedObjectDirectory;
  807. }
  808. POBJECT_ATTRIBUTES
  809. WmipBaseFormatObjectAttributes(
  810. OUT POBJECT_ATTRIBUTES ObjectAttributes,
  811. IN PSECURITY_ATTRIBUTES SecurityAttributes,
  812. IN PUNICODE_STRING ObjectName
  813. )
  814. /*++
  815. Routine Description:
  816. This function transforms a Win32 security attributes structure into
  817. an NT object attributes structure. It returns the address of the
  818. resulting structure (or NULL if SecurityAttributes was not
  819. specified).
  820. Arguments:
  821. ObjectAttributes - Returns an initialized NT object attributes
  822. structure that contains a superset of the information provided
  823. by the security attributes structure.
  824. SecurityAttributes - Supplies the address of a security attributes
  825. structure that needs to be transformed into an NT object
  826. attributes structure.
  827. ObjectName - Supplies a name for the object relative to the
  828. BaseNamedObjectDirectory object directory.
  829. Return Value:
  830. NULL - A value of null should be used to mimic the behavior of the
  831. specified SecurityAttributes structure.
  832. NON-NULL - Returns the ObjectAttributes value. The structure is
  833. properly initialized by this function.
  834. --*/
  835. {
  836. HANDLE RootDirectory;
  837. ULONG Attributes;
  838. PVOID SecurityDescriptor;
  839. if ( ARGUMENT_PRESENT(SecurityAttributes) ||
  840. ARGUMENT_PRESENT(ObjectName) ) {
  841. if ( ARGUMENT_PRESENT(ObjectName) ) {
  842. RootDirectory = WmipBaseGetNamedObjectDirectory();
  843. }
  844. else {
  845. RootDirectory = NULL;
  846. }
  847. if ( SecurityAttributes ) {
  848. Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
  849. SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
  850. }
  851. else {
  852. Attributes = 0;
  853. SecurityDescriptor = NULL;
  854. }
  855. if ( ARGUMENT_PRESENT(ObjectName) ) {
  856. Attributes |= OBJ_OPENIF;
  857. }
  858. InitializeObjectAttributes(
  859. ObjectAttributes,
  860. ObjectName,
  861. Attributes,
  862. RootDirectory,
  863. SecurityDescriptor
  864. );
  865. return ObjectAttributes;
  866. }
  867. else {
  868. return NULL;
  869. }
  870. }
  871. HANDLE
  872. WINAPI
  873. WmipCreateFileA(
  874. LPCSTR lpFileName,
  875. DWORD dwDesiredAccess,
  876. DWORD dwShareMode,
  877. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  878. DWORD dwCreationDisposition,
  879. DWORD dwFlagsAndAttributes,
  880. HANDLE hTemplateFile
  881. )
  882. /*++
  883. Routine Description:
  884. ANSI thunk to CreateFileW
  885. --*/
  886. {
  887. PUNICODE_STRING Unicode;
  888. Unicode = WmipBasep8BitStringToStaticUnicodeString( lpFileName );
  889. if (Unicode == NULL) {
  890. return INVALID_HANDLE_VALUE;
  891. }
  892. return WmipCreateFileW( Unicode->Buffer,
  893. dwDesiredAccess,
  894. dwShareMode,
  895. lpSecurityAttributes,
  896. dwCreationDisposition,
  897. dwFlagsAndAttributes,
  898. hTemplateFile
  899. );
  900. }
  901. HANDLE
  902. APIENTRY
  903. WmipCreateEventW(
  904. LPSECURITY_ATTRIBUTES lpEventAttributes,
  905. BOOL bManualReset,
  906. BOOL bInitialState,
  907. LPCWSTR lpName
  908. )
  909. /*++
  910. Routine Description:
  911. An event object is created and a handle opened for access to the
  912. object with the CreateEvent function.
  913. The CreateEvent function creates an event object with the specified
  914. initial state. If an event is in the Signaled state (TRUE), a wait
  915. operation on the event does not block. If the event is in the Not-
  916. Signaled state (FALSE), a wait operation on the event blocks until
  917. the specified event attains a state of Signaled, or the timeout
  918. value is exceeded.
  919. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
  920. object type specific access flags are valid for event objects:
  921. - EVENT_MODIFY_STATE - Modify state access (set and reset) to
  922. the event is desired.
  923. - SYNCHRONIZE - Synchronization access (wait) to the event is
  924. desired.
  925. - EVENT_ALL_ACCESS - This set of access flags specifies all of
  926. the possible access flags for an event object.
  927. Arguments:
  928. lpEventAttributes - An optional parameter that may be used to
  929. specify the attributes of the new event. If the parameter is
  930. not specified, then the event is created without a security
  931. descriptor, and the resulting handle is not inherited on process
  932. creation.
  933. bManualReset - Supplies a flag which if TRUE specifies that the
  934. event must be manually reset. If the value is FALSE, then after
  935. releasing a single waiter, the system automaticaly resets the
  936. event.
  937. bInitialState - The initial state of the event object, one of TRUE
  938. or FALSE. If the InitialState is specified as TRUE, the event's
  939. current state value is set to one, otherwise it is set to zero.
  940. lpName - Optional unicode name of event
  941. Return Value:
  942. NON-NULL - Returns a handle to the new event. The handle has full
  943. access to the new event and may be used in any API that requires
  944. a handle to an event object.
  945. FALSE/NULL - The operation failed. Extended error status is available
  946. using WmipGetLastError.
  947. --*/
  948. {
  949. NTSTATUS Status;
  950. OBJECT_ATTRIBUTES Obja;
  951. POBJECT_ATTRIBUTES pObja;
  952. HANDLE Handle;
  953. UNICODE_STRING ObjectName;
  954. PWCHAR pstrNewObjName = NULL;
  955. if ( ARGUMENT_PRESENT(lpName) ) {
  956. if (gpTermsrvFormatObjectName &&
  957. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  958. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  959. } else {
  960. RtlInitUnicodeString(&ObjectName,lpName);
  961. }
  962. pObja = WmipBaseFormatObjectAttributes(&Obja,lpEventAttributes,&ObjectName);
  963. }
  964. else {
  965. pObja = WmipBaseFormatObjectAttributes(&Obja,lpEventAttributes,NULL);
  966. }
  967. Status = NtCreateEvent(
  968. &Handle,
  969. EVENT_ALL_ACCESS,
  970. pObja,
  971. bManualReset ? NotificationEvent : SynchronizationEvent,
  972. (BOOLEAN)bInitialState
  973. );
  974. if (pstrNewObjName) {
  975. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  976. }
  977. if ( NT_SUCCESS(Status) ) {
  978. if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
  979. WmipSetLastError(ERROR_ALREADY_EXISTS);
  980. }
  981. else {
  982. WmipSetLastError(0);
  983. }
  984. return Handle;
  985. }
  986. else {
  987. WmipBaseSetLastNTError(Status);
  988. return NULL;
  989. }
  990. }
  991. //
  992. // Event Services
  993. //
  994. HANDLE
  995. APIENTRY
  996. WmipCreateEventA(
  997. LPSECURITY_ATTRIBUTES lpEventAttributes,
  998. BOOL bManualReset,
  999. BOOL bInitialState,
  1000. LPCSTR lpName
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. ANSI thunk to CreateEventW
  1005. --*/
  1006. {
  1007. PUNICODE_STRING Unicode;
  1008. ANSI_STRING AnsiString;
  1009. NTSTATUS Status;
  1010. LPCWSTR NameBuffer;
  1011. NameBuffer = NULL;
  1012. if ( ARGUMENT_PRESENT(lpName) ) {
  1013. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  1014. RtlInitAnsiString(&AnsiString,lpName);
  1015. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  1016. if ( !NT_SUCCESS(Status) ) {
  1017. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1018. WmipSetLastError(ERROR_FILENAME_EXCED_RANGE);
  1019. }
  1020. else {
  1021. WmipBaseSetLastNTError(Status);
  1022. }
  1023. return NULL;
  1024. }
  1025. NameBuffer = (LPCWSTR)Unicode->Buffer;
  1026. }
  1027. return WmipCreateEventW(
  1028. lpEventAttributes,
  1029. bManualReset,
  1030. bInitialState,
  1031. NameBuffer
  1032. );
  1033. }
  1034. DWORD
  1035. WINAPI
  1036. WmipSetFilePointer(
  1037. HANDLE hFile,
  1038. LONG lDistanceToMove,
  1039. PLONG lpDistanceToMoveHigh,
  1040. DWORD dwMoveMethod
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. An open file's file pointer can be set using SetFilePointer.
  1045. The purpose of this function is to update the current value of a
  1046. file's file pointer. Care should be taken in multi-threaded
  1047. applications that have multiple threads sharing a file handle with
  1048. each thread updating the file pointer and then doing a read. This
  1049. sequence should be treated as a critical section of code and should
  1050. be protected using either a critical section object or a mutex
  1051. object.
  1052. This API provides the same functionality as DOS (int 21h, function
  1053. 42h) and OS/2's DosSetFilePtr.
  1054. Arguments:
  1055. hFile - Supplies an open handle to a file whose file pointer is to be
  1056. moved. The file handle must have been created with
  1057. GENERIC_READ or GENERIC_WRITE access to the file.
  1058. lDistanceToMove - Supplies the number of bytes to move the file
  1059. pointer. A positive value moves the pointer forward in the file
  1060. and a negative value moves backwards in the file.
  1061. lpDistanceToMoveHigh - An optional parameter that if specified
  1062. supplies the high order 32-bits of the 64-bit distance to move.
  1063. If the value of this parameter is NULL, this API can only
  1064. operate on files whose maximum size is (2**32)-2. If this
  1065. parameter is specified, than the maximum file size is (2**64)-2.
  1066. This value also returns the high order 32-bits of the new value
  1067. of the file pointer. If this value, and the return value
  1068. are 0xffffffff, then an error is indicated.
  1069. dwMoveMethod - Supplies a value that specifies the starting point
  1070. for the file pointer move.
  1071. FILE_BEGIN - The starting point is zero or the beginning of the
  1072. file. If FILE_BEGIN is specified, then DistanceToMove is
  1073. interpreted as an unsigned location for the new
  1074. file pointer.
  1075. FILE_CURRENT - The current value of the file pointer is used as
  1076. the starting point.
  1077. FILE_END - The current end of file position is used as the
  1078. starting point.
  1079. Return Value:
  1080. Not -1 - Returns the low order 32-bits of the new value of the file
  1081. pointer.
  1082. 0xffffffff - If the value of lpDistanceToMoveHigh was NULL, then The
  1083. operation failed. Extended error status is available using
  1084. WmipGetLastError. Otherwise, this is the low order 32-bits of the
  1085. new value of the file pointer.
  1086. --*/
  1087. {
  1088. NTSTATUS Status;
  1089. IO_STATUS_BLOCK IoStatusBlock;
  1090. FILE_POSITION_INFORMATION CurrentPosition;
  1091. FILE_STANDARD_INFORMATION StandardInfo;
  1092. LARGE_INTEGER Large;
  1093. if (CONSOLE_HANDLE(hFile)) {
  1094. WmipBaseSetLastNTError(STATUS_INVALID_HANDLE);
  1095. return (DWORD)-1;
  1096. }
  1097. if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)) {
  1098. Large.HighPart = *lpDistanceToMoveHigh;
  1099. Large.LowPart = lDistanceToMove;
  1100. }
  1101. else {
  1102. Large.QuadPart = lDistanceToMove;
  1103. }
  1104. switch (dwMoveMethod) {
  1105. case FILE_BEGIN :
  1106. CurrentPosition.CurrentByteOffset = Large;
  1107. break;
  1108. case FILE_CURRENT :
  1109. //
  1110. // Get the current position of the file pointer
  1111. //
  1112. Status = NtQueryInformationFile(
  1113. hFile,
  1114. &IoStatusBlock,
  1115. &CurrentPosition,
  1116. sizeof(CurrentPosition),
  1117. FilePositionInformation
  1118. );
  1119. if ( !NT_SUCCESS(Status) ) {
  1120. WmipBaseSetLastNTError(Status);
  1121. return (DWORD)-1;
  1122. }
  1123. CurrentPosition.CurrentByteOffset.QuadPart += Large.QuadPart;
  1124. break;
  1125. case FILE_END :
  1126. Status = NtQueryInformationFile(
  1127. hFile,
  1128. &IoStatusBlock,
  1129. &StandardInfo,
  1130. sizeof(StandardInfo),
  1131. FileStandardInformation
  1132. );
  1133. if ( !NT_SUCCESS(Status) ) {
  1134. WmipBaseSetLastNTError(Status);
  1135. return (DWORD)-1;
  1136. }
  1137. CurrentPosition.CurrentByteOffset.QuadPart =
  1138. StandardInfo.EndOfFile.QuadPart + Large.QuadPart;
  1139. break;
  1140. default:
  1141. WmipSetLastError(ERROR_INVALID_PARAMETER);
  1142. return (DWORD)-1;
  1143. break;
  1144. }
  1145. //
  1146. // If the resulting file position is negative, or if the app is not
  1147. // prepared for greater than
  1148. // then 32 bits than fail
  1149. //
  1150. if ( CurrentPosition.CurrentByteOffset.QuadPart < 0 ) {
  1151. WmipSetLastError(ERROR_NEGATIVE_SEEK);
  1152. return (DWORD)-1;
  1153. }
  1154. if ( !ARGUMENT_PRESENT(lpDistanceToMoveHigh) &&
  1155. (CurrentPosition.CurrentByteOffset.HighPart & MAXLONG) ) {
  1156. WmipSetLastError(ERROR_INVALID_PARAMETER);
  1157. return (DWORD)-1;
  1158. }
  1159. //
  1160. // Set the current file position
  1161. //
  1162. Status = NtSetInformationFile(
  1163. hFile,
  1164. &IoStatusBlock,
  1165. &CurrentPosition,
  1166. sizeof(CurrentPosition),
  1167. FilePositionInformation
  1168. );
  1169. if ( NT_SUCCESS(Status) ) {
  1170. if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){
  1171. *lpDistanceToMoveHigh = CurrentPosition.CurrentByteOffset.HighPart;
  1172. }
  1173. if ( CurrentPosition.CurrentByteOffset.LowPart == -1 ) {
  1174. WmipSetLastError(0);
  1175. }
  1176. return CurrentPosition.CurrentByteOffset.LowPart;
  1177. }
  1178. else {
  1179. WmipBaseSetLastNTError(Status);
  1180. if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){
  1181. *lpDistanceToMoveHigh = -1;
  1182. }
  1183. return (DWORD)-1;
  1184. }
  1185. }
  1186. BOOL
  1187. WINAPI
  1188. WmipReadFile(
  1189. HANDLE hFile,
  1190. LPVOID lpBuffer,
  1191. DWORD nNumberOfBytesToRead,
  1192. LPDWORD lpNumberOfBytesRead,
  1193. LPOVERLAPPED lpOverlapped
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. Data can be read from a file using ReadFile.
  1198. This API is used to read data from a file. Data is read from the
  1199. file from the position indicated by the file pointer. After the
  1200. read completes, the file pointer is adjusted by the number of bytes
  1201. actually read. A return value of TRUE coupled with a bytes read of
  1202. 0 indicates that the file pointer was beyond the current end of the
  1203. file at the time of the read.
  1204. Arguments:
  1205. hFile - Supplies an open handle to a file that is to be read. The
  1206. file handle must have been created with GENERIC_READ access to
  1207. the file.
  1208. lpBuffer - Supplies the address of a buffer to receive the data read
  1209. from the file.
  1210. nNumberOfBytesToRead - Supplies the number of bytes to read from the
  1211. file.
  1212. lpNumberOfBytesRead - Returns the number of bytes read by this call.
  1213. This parameter is always set to 0 before doing any IO or error
  1214. checking.
  1215. lpOverlapped - Optionally points to an OVERLAPPED structure to be used with the
  1216. request. If NULL then the transfer starts at the current file position
  1217. and ReadFile will not return until the operation completes.
  1218. If the handle hFile was created without specifying FILE_FLAG_OVERLAPPED
  1219. the file pointer is moved to the specified offset plus
  1220. lpNumberOfBytesRead before ReadFile returns. ReadFile will wait for the
  1221. request to complete before returning (it will not return
  1222. ERROR_IO_PENDING).
  1223. When FILE_FLAG_OVERLAPPED is specified, ReadFile may return
  1224. ERROR_IO_PENDING to allow the calling function to continue processing
  1225. while the operation completes. The event (or hFile if hEvent is NULL) will
  1226. be set to the signalled state upon completion of the request.
  1227. When the handle is created with FILE_FLAG_OVERLAPPED and lpOverlapped
  1228. is set to NULL, ReadFile will return ERROR_INVALID_PARAMTER because
  1229. the file offset is required.
  1230. Return Value:
  1231. TRUE - The operation was successul.
  1232. FALSE - The operation failed. Extended error status is available
  1233. using WmipGetLastError.
  1234. --*/
  1235. {
  1236. NTSTATUS Status;
  1237. IO_STATUS_BLOCK IoStatusBlock;
  1238. PPEB Peb;
  1239. DWORD InputMode;
  1240. if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
  1241. *lpNumberOfBytesRead = 0;
  1242. }
  1243. Peb = NtCurrentPeb();
  1244. switch( HandleToUlong(hFile) ) {
  1245. case STD_INPUT_HANDLE: hFile = Peb->ProcessParameters->StandardInput;
  1246. break;
  1247. case STD_OUTPUT_HANDLE: hFile = Peb->ProcessParameters->StandardOutput;
  1248. break;
  1249. case STD_ERROR_HANDLE: hFile = Peb->ProcessParameters->StandardError;
  1250. break;
  1251. }
  1252. if ( ARGUMENT_PRESENT( lpOverlapped ) ) {
  1253. LARGE_INTEGER Li;
  1254. lpOverlapped->Internal = (DWORD)STATUS_PENDING;
  1255. Li.LowPart = lpOverlapped->Offset;
  1256. Li.HighPart = lpOverlapped->OffsetHigh;
  1257. Status = NtReadFile(
  1258. hFile,
  1259. lpOverlapped->hEvent,
  1260. NULL,
  1261. (ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
  1262. (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
  1263. lpBuffer,
  1264. nNumberOfBytesToRead,
  1265. &Li,
  1266. NULL
  1267. );
  1268. if ( NT_SUCCESS(Status) && Status != STATUS_PENDING) {
  1269. if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
  1270. try {
  1271. *lpNumberOfBytesRead = (DWORD)lpOverlapped->InternalHigh;
  1272. }
  1273. except(EXCEPTION_EXECUTE_HANDLER) {
  1274. *lpNumberOfBytesRead = 0;
  1275. }
  1276. }
  1277. return TRUE;
  1278. }
  1279. else
  1280. if (Status == STATUS_END_OF_FILE) {
  1281. if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
  1282. *lpNumberOfBytesRead = 0;
  1283. }
  1284. WmipBaseSetLastNTError(Status);
  1285. return FALSE;
  1286. }
  1287. else {
  1288. WmipBaseSetLastNTError(Status);
  1289. return FALSE;
  1290. }
  1291. }
  1292. else
  1293. {
  1294. Status = NtReadFile(
  1295. hFile,
  1296. NULL,
  1297. NULL,
  1298. NULL,
  1299. &IoStatusBlock,
  1300. lpBuffer,
  1301. nNumberOfBytesToRead,
  1302. NULL,
  1303. NULL
  1304. );
  1305. if ( Status == STATUS_PENDING) {
  1306. // Operation must complete before return & IoStatusBlock destroyed
  1307. Status = NtWaitForSingleObject( hFile, FALSE, NULL );
  1308. if ( NT_SUCCESS(Status)) {
  1309. Status = IoStatusBlock.Status;
  1310. }
  1311. }
  1312. if ( NT_SUCCESS(Status) ) {
  1313. *lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
  1314. return TRUE;
  1315. }
  1316. else
  1317. if (Status == STATUS_END_OF_FILE) {
  1318. *lpNumberOfBytesRead = 0;
  1319. return TRUE;
  1320. }
  1321. else {
  1322. if ( NT_WARNING(Status) ) {
  1323. *lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
  1324. }
  1325. WmipBaseSetLastNTError(Status);
  1326. return FALSE;
  1327. }
  1328. }
  1329. }
  1330. BOOL
  1331. WmipCloseHandle(
  1332. HANDLE hObject
  1333. )
  1334. {
  1335. NTSTATUS Status;
  1336. Status = NtClose(hObject);
  1337. if ( NT_SUCCESS(Status) ) {
  1338. return TRUE;
  1339. } else {
  1340. WmipBaseSetLastNTError(Status);
  1341. return FALSE;
  1342. }
  1343. }
  1344. DWORD
  1345. APIENTRY
  1346. WmipWaitForSingleObjectEx(
  1347. HANDLE hHandle,
  1348. DWORD dwMilliseconds,
  1349. BOOL bAlertable
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. A wait operation on a waitable object is accomplished with the
  1354. WaitForSingleObjectEx function.
  1355. Waiting on an object checks the current state of the object. If the
  1356. current state of the object allows continued execution, any
  1357. adjustments to the object state are made (for example, decrementing
  1358. the semaphore count for a semaphore object) and the thread continues
  1359. execution. If the current state of the object does not allow
  1360. continued execution, the thread is placed into the wait state
  1361. pending the change of the object's state or time-out.
  1362. If the bAlertable parameter is FALSE, the only way the wait
  1363. terminates is because the specified timeout period expires, or
  1364. because the specified object entered the signaled state. If the
  1365. bAlertable parameter is TRUE, then the wait can return due to any
  1366. one of the above wait termination conditions, or because an I/O
  1367. completion callback terminated the wait early (return value of
  1368. WAIT_IO_COMPLETION).
  1369. Arguments:
  1370. hHandle - An open handle to a waitable object. The handle must have
  1371. SYNCHRONIZE access to the object.
  1372. dwMilliseconds - A time-out value that specifies the relative time,
  1373. in milliseconds, over which the wait is to be completed. A
  1374. timeout value of 0 specified that the wait is to timeout
  1375. immediately. This allows an application to test an object to
  1376. determine if it is in the signaled state. A timeout value of
  1377. 0xffffffff specifies an infinite timeout period.
  1378. bAlertable - Supplies a flag that controls whether or not the
  1379. wait may terminate early due to an I/O completion callback.
  1380. A value of TRUE allows this API to complete early due to an I/O
  1381. completion callback. A value of FALSE will not allow I/O
  1382. completion callbacks to terminate this call early.
  1383. Return Value:
  1384. WAIT_TIME_OUT - Indicates that the wait was terminated due to the
  1385. TimeOut conditions.
  1386. 0 - indicates the specified object attained a Signaled
  1387. state thus completing the wait.
  1388. 0xffffffff - The wait terminated due to an error. WmipGetLastError may be
  1389. used to get additional error information.
  1390. WAIT_ABANDONED - indicates the specified object attained a Signaled
  1391. state but was abandoned.
  1392. WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
  1393. completion callbacks.
  1394. --*/
  1395. {
  1396. NTSTATUS Status;
  1397. LARGE_INTEGER TimeOut;
  1398. PLARGE_INTEGER pTimeOut;
  1399. PPEB Peb;
  1400. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  1401. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  1402. __try {
  1403. Peb = NtCurrentPeb();
  1404. switch( HandleToUlong(hHandle) ) {
  1405. case STD_INPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardInput;
  1406. break;
  1407. case STD_OUTPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardOutput;
  1408. break;
  1409. case STD_ERROR_HANDLE: hHandle = Peb->ProcessParameters->StandardError;
  1410. break;
  1411. }
  1412. pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
  1413. rewait:
  1414. Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
  1415. if ( !NT_SUCCESS(Status) ) {
  1416. WmipBaseSetLastNTError(Status);
  1417. Status = (NTSTATUS)0xffffffff;
  1418. }
  1419. else {
  1420. if ( bAlertable && Status == STATUS_ALERTED ) {
  1421. goto rewait;
  1422. }
  1423. }
  1424. } __finally {
  1425. RtlDeactivateActivationContextUnsafeFast(&Frame);
  1426. }
  1427. return (DWORD)Status;
  1428. }
  1429. BOOL
  1430. WINAPI
  1431. WmipGetOverlappedResult(
  1432. HANDLE hFile,
  1433. LPOVERLAPPED lpOverlapped,
  1434. LPDWORD lpNumberOfBytesTransferred,
  1435. BOOL bWait
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. The GetOverlappedResult function returns the result of the last
  1440. operation that used lpOverlapped and returned ERROR_IO_PENDING.
  1441. Arguments:
  1442. hFile - Supplies the open handle to the file that the overlapped
  1443. structure lpOverlapped was supplied to ReadFile, WriteFile,
  1444. ConnectNamedPipe, WaitNamedPipe or TransactNamedPipe.
  1445. lpOverlapped - Points to an OVERLAPPED structure previously supplied to
  1446. ReadFile, WriteFile, ConnectNamedPipe, WaitNamedPipe or
  1447. TransactNamedPipe.
  1448. lpNumberOfBytesTransferred - Returns the number of bytes transferred
  1449. by the operation.
  1450. bWait - A boolean value that affects the behavior when the operation
  1451. is still in progress. If TRUE and the operation is still in progress,
  1452. GetOverlappedResult will wait for the operation to complete before
  1453. returning. If FALSE and the operation is incomplete,
  1454. GetOverlappedResult will return FALSE. In this case the extended
  1455. error information available from the WmipGetLastError function will be
  1456. set to ERROR_IO_INCOMPLETE.
  1457. Return Value:
  1458. TRUE -- The operation was successful, the pipe is in the
  1459. connected state.
  1460. FALSE -- The operation failed. Extended error status is available using
  1461. WmipGetLastError.
  1462. --*/
  1463. {
  1464. DWORD WaitReturn;
  1465. //
  1466. // Did caller specify an event to the original operation or was the
  1467. // default (file handle) used?
  1468. //
  1469. if (lpOverlapped->Internal == (DWORD)STATUS_PENDING ) {
  1470. if ( bWait ) {
  1471. WaitReturn = WmipWaitForSingleObject(
  1472. ( lpOverlapped->hEvent != NULL ) ?
  1473. lpOverlapped->hEvent : hFile,
  1474. INFINITE
  1475. );
  1476. }
  1477. else {
  1478. WaitReturn = WAIT_TIMEOUT;
  1479. }
  1480. if ( WaitReturn == WAIT_TIMEOUT ) {
  1481. // !bWait and event in not signalled state
  1482. WmipSetLastError( ERROR_IO_INCOMPLETE );
  1483. return FALSE;
  1484. }
  1485. if ( WaitReturn != 0 ) {
  1486. return FALSE; // WaitForSingleObject calls BaseSetLastError
  1487. }
  1488. }
  1489. *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
  1490. if ( NT_SUCCESS((NTSTATUS)lpOverlapped->Internal) ){
  1491. return TRUE;
  1492. }
  1493. else {
  1494. WmipBaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );
  1495. return FALSE;
  1496. }
  1497. }
  1498. PLARGE_INTEGER
  1499. WmipBaseFormatTimeOut(
  1500. OUT PLARGE_INTEGER TimeOut,
  1501. IN DWORD Milliseconds
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This function translates a Win32 style timeout to an NT relative
  1506. timeout value.
  1507. Arguments:
  1508. TimeOut - Returns an initialized NT timeout value that is equivalent
  1509. to the Milliseconds parameter.
  1510. Milliseconds - Supplies the timeout value in milliseconds. A value
  1511. of -1 indicates indefinite timeout.
  1512. Return Value:
  1513. NULL - A value of null should be used to mimic the behavior of the
  1514. specified Milliseconds parameter.
  1515. NON-NULL - Returns the TimeOut value. The structure is properly
  1516. initialized by this function.
  1517. --*/
  1518. {
  1519. if ( (LONG) Milliseconds == -1 ) {
  1520. return( NULL );
  1521. }
  1522. TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
  1523. TimeOut->QuadPart *= -1;
  1524. return TimeOut;
  1525. }
  1526. DWORD
  1527. WmipWaitForSingleObject(
  1528. HANDLE hHandle,
  1529. DWORD dwMilliseconds
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. A wait operation on a waitable object is accomplished with the
  1534. WaitForSingleObject function.
  1535. Waiting on an object checks the current state of the object. If the
  1536. current state of the object allows continued execution, any
  1537. adjustments to the object state are made (for example, decrementing
  1538. the semaphore count for a semaphore object) and the thread continues
  1539. execution. If the current state of the object does not allow
  1540. continued execution, the thread is placed into the wait state
  1541. pending the change of the object's state or time-out.
  1542. Arguments:
  1543. hHandle - An open handle to a waitable object. The handle must have
  1544. SYNCHRONIZE access to the object.
  1545. dwMilliseconds - A time-out value that specifies the relative time,
  1546. in milliseconds, over which the wait is to be completed. A
  1547. timeout value of 0 specified that the wait is to timeout
  1548. immediately. This allows an application to test an object to
  1549. determine if it is in the signaled state. A timeout value of -1
  1550. specifies an infinite timeout period.
  1551. Return Value:
  1552. WAIT_TIME_OUT - Indicates that the wait was terminated due to the
  1553. TimeOut conditions.
  1554. 0 - indicates the specified object attained a Signaled
  1555. state thus completing the wait.
  1556. WAIT_ABANDONED - indicates the specified object attained a Signaled
  1557. state but was abandoned.
  1558. --*/
  1559. {
  1560. return WmipWaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
  1561. }
  1562. BOOL
  1563. WINAPI
  1564. WmipDeviceIoControl(
  1565. HANDLE hDevice,
  1566. DWORD dwIoControlCode,
  1567. LPVOID lpInBuffer,
  1568. DWORD nInBufferSize,
  1569. LPVOID lpOutBuffer,
  1570. DWORD nOutBufferSize,
  1571. LPDWORD lpBytesReturned,
  1572. LPOVERLAPPED lpOverlapped
  1573. )
  1574. /*++
  1575. Routine Description:
  1576. An operation on a device may be performed by calling the device driver
  1577. directly using the DeviceIoContrl function.
  1578. The device driver must first be opened to get a valid handle.
  1579. Arguments:
  1580. hDevice - Supplies an open handle a device on which the operation is to
  1581. be performed.
  1582. dwIoControlCode - Supplies the control code for the operation. This
  1583. control code determines on which type of device the operation must
  1584. be performed and determines exactly what operation is to be
  1585. performed.
  1586. lpInBuffer - Suplies an optional pointer to an input buffer that contains
  1587. the data required to perform the operation. Whether or not the
  1588. buffer is actually optional is dependent on the IoControlCode.
  1589. nInBufferSize - Supplies the length of the input buffer in bytes.
  1590. lpOutBuffer - Suplies an optional pointer to an output buffer into which
  1591. the output data will be copied. Whether or not the buffer is actually
  1592. optional is dependent on the IoControlCode.
  1593. nOutBufferSize - Supplies the length of the output buffer in bytes.
  1594. lpBytesReturned - Supplies a pointer to a dword which will receive the
  1595. actual length of the data returned in the output buffer.
  1596. lpOverlapped - An optional parameter that supplies an overlap structure to
  1597. be used with the request. If NULL or the handle was created without
  1598. FILE_FLAG_OVERLAPPED then the DeviceIoControl will not return until
  1599. the operation completes.
  1600. When lpOverlapped is supplied and FILE_FLAG_OVERLAPPED was specified
  1601. when the handle was created, DeviceIoControl may return
  1602. ERROR_IO_PENDING to allow the caller to continue processing while the
  1603. operation completes. The event (or File handle if hEvent == NULL) will
  1604. be set to the not signalled state before ERROR_IO_PENDING is
  1605. returned. The event will be set to the signalled state upon completion
  1606. of the request. GetOverlappedResult is used to determine the result
  1607. when ERROR_IO_PENDING is returned.
  1608. Return Value:
  1609. TRUE -- The operation was successful.
  1610. FALSE -- The operation failed. Extended error status is available using
  1611. WmipGetLastError.
  1612. --*/
  1613. {
  1614. NTSTATUS Status;
  1615. BOOLEAN DevIoCtl;
  1616. if ( dwIoControlCode >> 16 == FILE_DEVICE_FILE_SYSTEM ) {
  1617. DevIoCtl = FALSE;
  1618. }
  1619. else {
  1620. DevIoCtl = TRUE;
  1621. }
  1622. if ( ARGUMENT_PRESENT( lpOverlapped ) ) {
  1623. lpOverlapped->Internal = (DWORD)STATUS_PENDING;
  1624. if ( DevIoCtl ) {
  1625. Status = NtDeviceIoControlFile(
  1626. hDevice,
  1627. lpOverlapped->hEvent,
  1628. NULL, // APC routine
  1629. (ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
  1630. (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
  1631. dwIoControlCode, // IoControlCode
  1632. lpInBuffer, // Buffer for data to the FS
  1633. nInBufferSize,
  1634. lpOutBuffer, // OutputBuffer for data from the FS
  1635. nOutBufferSize // OutputBuffer Length
  1636. );
  1637. }
  1638. else {
  1639. Status = NtFsControlFile(
  1640. hDevice,
  1641. lpOverlapped->hEvent,
  1642. NULL, // APC routine
  1643. (ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
  1644. (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
  1645. dwIoControlCode, // IoControlCode
  1646. lpInBuffer, // Buffer for data to the FS
  1647. nInBufferSize,
  1648. lpOutBuffer, // OutputBuffer for data from the FS
  1649. nOutBufferSize // OutputBuffer Length
  1650. );
  1651. }
  1652. // handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly
  1653. if ( !NT_ERROR(Status) && ARGUMENT_PRESENT(lpBytesReturned) ) {
  1654. try {
  1655. *lpBytesReturned = (DWORD)lpOverlapped->InternalHigh;
  1656. }
  1657. except(EXCEPTION_EXECUTE_HANDLER) {
  1658. *lpBytesReturned = 0;
  1659. }
  1660. }
  1661. if ( NT_SUCCESS(Status) && Status != STATUS_PENDING) {
  1662. return TRUE;
  1663. }
  1664. else {
  1665. WmipBaseSetLastNTError(Status);
  1666. return FALSE;
  1667. }
  1668. }
  1669. else
  1670. {
  1671. IO_STATUS_BLOCK Iosb;
  1672. if ( DevIoCtl ) {
  1673. Status = NtDeviceIoControlFile(
  1674. hDevice,
  1675. NULL,
  1676. NULL, // APC routine
  1677. NULL, // APC Context
  1678. &Iosb,
  1679. dwIoControlCode, // IoControlCode
  1680. lpInBuffer, // Buffer for data to the FS
  1681. nInBufferSize,
  1682. lpOutBuffer, // OutputBuffer for data from the FS
  1683. nOutBufferSize // OutputBuffer Length
  1684. );
  1685. }
  1686. else {
  1687. Status = NtFsControlFile(
  1688. hDevice,
  1689. NULL,
  1690. NULL, // APC routine
  1691. NULL, // APC Context
  1692. &Iosb,
  1693. dwIoControlCode, // IoControlCode
  1694. lpInBuffer, // Buffer for data to the FS
  1695. nInBufferSize,
  1696. lpOutBuffer, // OutputBuffer for data from the FS
  1697. nOutBufferSize // OutputBuffer Length
  1698. );
  1699. }
  1700. if ( Status == STATUS_PENDING) {
  1701. // Operation must complete before return & Iosb destroyed
  1702. Status = NtWaitForSingleObject( hDevice, FALSE, NULL );
  1703. if ( NT_SUCCESS(Status)) {
  1704. Status = Iosb.Status;
  1705. }
  1706. }
  1707. if ( NT_SUCCESS(Status) ) {
  1708. *lpBytesReturned = (DWORD)Iosb.Information;
  1709. return TRUE;
  1710. }
  1711. else {
  1712. // handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly
  1713. if ( !NT_ERROR(Status) ) {
  1714. *lpBytesReturned = (DWORD)Iosb.Information;
  1715. }
  1716. WmipBaseSetLastNTError(Status);
  1717. return FALSE;
  1718. }
  1719. }
  1720. }
  1721. BOOL
  1722. WINAPI
  1723. WmipCancelIo(
  1724. HANDLE hFile
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. This routine cancels all of the outstanding I/O for the specified handle
  1729. for the specified file.
  1730. Arguments:
  1731. hFile - Supplies the handle to the file whose pending I/O is to be
  1732. canceled.
  1733. Return Value:
  1734. TRUE -- The operation was successful.
  1735. FALSE -- The operation failed. Extended error status is available using
  1736. WmipGetLastError.
  1737. --*/
  1738. {
  1739. NTSTATUS Status;
  1740. IO_STATUS_BLOCK IoStatusBlock;
  1741. //
  1742. // Simply cancel the I/O for the specified file.
  1743. //
  1744. Status = NtCancelIoFile(hFile, &IoStatusBlock);
  1745. if ( NT_SUCCESS(Status) ) {
  1746. return TRUE;
  1747. }
  1748. else {
  1749. WmipBaseSetLastNTError(Status);
  1750. return FALSE;
  1751. }
  1752. }
  1753. VOID
  1754. APIENTRY
  1755. WmipExitThread(
  1756. DWORD dwExitCode
  1757. )
  1758. {
  1759. RtlExitUserThread(dwExitCode);
  1760. }
  1761. DWORD
  1762. WINAPI
  1763. WmipGetCurrentProcessId(
  1764. VOID
  1765. )
  1766. /*++
  1767. Routine Description:
  1768. The process ID of the current process may be retrieved using
  1769. GetCurrentProcessId.
  1770. Arguments:
  1771. None.
  1772. Return Value:
  1773. Returns a unique value representing the process ID of the currently
  1774. executing process. The return value may be used to open a handle to
  1775. a process.
  1776. --*/
  1777. {
  1778. return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
  1779. }
  1780. DWORD
  1781. APIENTRY
  1782. WmipGetCurrentThreadId(
  1783. VOID
  1784. )
  1785. /*++
  1786. Routine Description:
  1787. The thread ID of the current thread may be retrieved using
  1788. GetCurrentThreadId.
  1789. Arguments:
  1790. None.
  1791. Return Value:
  1792. Returns a unique value representing the thread ID of the currently
  1793. executing thread. The return value may be used to identify a thread
  1794. in the system.
  1795. --*/
  1796. {
  1797. return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
  1798. }
  1799. HANDLE
  1800. WINAPI
  1801. WmipGetCurrentProcess(
  1802. VOID
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. A pseudo handle to the current process may be retrieved using
  1807. GetCurrentProcess.
  1808. A special constant is exported by Win32 that is interpreted as a
  1809. handle to the current process. This handle may be used to specify
  1810. the current process whenever a process handle is required. On
  1811. Win32, this handle has PROCESS_ALL_ACCESS to the current process.
  1812. On NT/Win32, this handle has the maximum access allowed by any
  1813. security descriptor placed on the current process.
  1814. Arguments:
  1815. None.
  1816. Return Value:
  1817. Returns the pseudo handle of the current process.
  1818. --*/
  1819. {
  1820. return NtCurrentProcess();
  1821. }
  1822. BOOL
  1823. WmipSetEvent(
  1824. HANDLE hEvent
  1825. )
  1826. /*++
  1827. Routine Description:
  1828. An event can be set to the signaled state (TRUE) with the SetEvent
  1829. function.
  1830. Setting the event causes the event to attain a state of Signaled,
  1831. which releases all currently waiting threads (for manual reset
  1832. events), or a single waiting thread (for automatic reset events).
  1833. Arguments:
  1834. hEvent - Supplies an open handle to an event object. The
  1835. handle must have EVENT_MODIFY_STATE access to the event.
  1836. Return Value:
  1837. TRUE - The operation was successful
  1838. FALSE/NULL - The operation failed. Extended error status is available
  1839. using WmipGetLastError.
  1840. --*/
  1841. {
  1842. NTSTATUS Status;
  1843. Status = NtSetEvent(hEvent,NULL);
  1844. if ( NT_SUCCESS(Status) ) {
  1845. return TRUE;
  1846. }
  1847. else {
  1848. WmipBaseSetLastNTError(Status);
  1849. return FALSE;
  1850. }
  1851. }
  1852. VOID
  1853. WINAPI
  1854. WmipGetSystemInfo(
  1855. LPSYSTEM_INFO lpSystemInfo
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. The GetSystemInfo function is used to return information about the
  1860. current system. This includes the processor type, page size, oem
  1861. id, and other interesting pieces of information.
  1862. Arguments:
  1863. lpSystemInfo - Returns information about the current system.
  1864. SYSTEM_INFO Structure:
  1865. WORD wProcessorArchitecture - returns the architecture of the
  1866. processors in the system: e.g. Intel, Mips, Alpha or PowerPC
  1867. DWORD dwPageSize - Returns the page size. This is specifies the
  1868. granularity of page protection and commitment.
  1869. LPVOID lpMinimumApplicationAddress - Returns the lowest memory
  1870. address accessible to applications and DLLs.
  1871. LPVOID lpMaximumApplicationAddress - Returns the highest memory
  1872. address accessible to applications and DLLs.
  1873. DWORD dwActiveProcessorMask - Returns a mask representing the
  1874. set of processors configured into the system. Bit 0 is
  1875. processor 0, bit 31 is processor 31.
  1876. DWORD dwNumberOfProcessors - Returns the number of processors in
  1877. the system.
  1878. WORD wProcessorLevel - Returns the level of the processors in the
  1879. system. All processors are assumed to be of the same level,
  1880. stepping, and are configured with the same options.
  1881. WORD wProcessorRevision - Returns the revision or stepping of the
  1882. processors in the system. All processors are assumed to be
  1883. of the same level, stepping, and are configured with the
  1884. same options.
  1885. Return Value:
  1886. None.
  1887. --*/
  1888. {
  1889. NTSTATUS Status;
  1890. SYSTEM_BASIC_INFORMATION BasicInfo;
  1891. SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
  1892. RtlZeroMemory(lpSystemInfo,sizeof(*lpSystemInfo));
  1893. Status = NtQuerySystemInformation(
  1894. SystemBasicInformation,
  1895. &BasicInfo,
  1896. sizeof(BasicInfo),
  1897. NULL
  1898. );
  1899. if ( !NT_SUCCESS(Status) ) {
  1900. return;
  1901. }
  1902. Status = NtQuerySystemInformation(
  1903. SystemProcessorInformation,
  1904. &ProcessorInfo,
  1905. sizeof(ProcessorInfo),
  1906. NULL
  1907. );
  1908. if ( !NT_SUCCESS(Status) ) {
  1909. return;
  1910. }
  1911. lpSystemInfo->wProcessorArchitecture = ProcessorInfo.ProcessorArchitecture;
  1912. lpSystemInfo->wReserved = 0;
  1913. lpSystemInfo->dwPageSize = BasicInfo.PageSize;
  1914. lpSystemInfo->lpMinimumApplicationAddress = (LPVOID)BasicInfo.MinimumUserModeAddress;
  1915. lpSystemInfo->lpMaximumApplicationAddress = (LPVOID)BasicInfo.MaximumUserModeAddress;
  1916. lpSystemInfo->dwActiveProcessorMask = BasicInfo.ActiveProcessorsAffinityMask;
  1917. lpSystemInfo->dwNumberOfProcessors = BasicInfo.NumberOfProcessors;
  1918. lpSystemInfo->wProcessorLevel = ProcessorInfo.ProcessorLevel;
  1919. lpSystemInfo->wProcessorRevision = ProcessorInfo.ProcessorRevision;
  1920. if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
  1921. if (ProcessorInfo.ProcessorLevel == 3) {
  1922. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_386;
  1923. }
  1924. else
  1925. if (ProcessorInfo.ProcessorLevel == 4) {
  1926. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_486;
  1927. }
  1928. else {
  1929. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_PENTIUM;
  1930. }
  1931. }
  1932. else
  1933. if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS) {
  1934. lpSystemInfo->dwProcessorType = PROCESSOR_MIPS_R4000;
  1935. }
  1936. else
  1937. if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) {
  1938. lpSystemInfo->dwProcessorType = PROCESSOR_ALPHA_21064;
  1939. }
  1940. else
  1941. if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC) {
  1942. lpSystemInfo->dwProcessorType = 604; // backward compatibility
  1943. }
  1944. else
  1945. if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
  1946. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_IA64;
  1947. }
  1948. else {
  1949. lpSystemInfo->dwProcessorType = 0;
  1950. }
  1951. lpSystemInfo->dwAllocationGranularity = BasicInfo.AllocationGranularity;
  1952. //
  1953. // for apps less than 3.51, then return 0 in dwReserved. This allows borlands
  1954. // debugger to continue to run since it mistakenly used dwReserved
  1955. // as AllocationGranularity
  1956. //
  1957. /* commented by Digvijay
  1958. if ( WmipGetProcessVersion(0) < 0x30033 ) {
  1959. lpSystemInfo->wProcessorLevel = 0;
  1960. lpSystemInfo->wProcessorRevision = 0;
  1961. }*/
  1962. return;
  1963. }
  1964. VOID
  1965. WINAPI
  1966. WmipGlobalMemoryStatus(
  1967. LPMEMORYSTATUS lpBuffer
  1968. )
  1969. {
  1970. DWORD NumberOfPhysicalPages;
  1971. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  1972. VM_COUNTERS VmCounters;
  1973. QUOTA_LIMITS QuotaLimits;
  1974. NTSTATUS Status;
  1975. PPEB Peb;
  1976. PIMAGE_NT_HEADERS NtHeaders;
  1977. DWORDLONG Memory64;
  1978. #if defined(BUILD_WOW6432) || defined(_WIN64)
  1979. Status = NtQuerySystemInformation(SystemBasicInformation,
  1980. &SysInfo,
  1981. sizeof(SYSTEM_BASIC_INFORMATION),
  1982. NULL
  1983. );
  1984. if (!NT_SUCCESS(Status)) {
  1985. return;
  1986. }
  1987. #endif
  1988. Status = NtQuerySystemInformation(
  1989. SystemPerformanceInformation,
  1990. &PerfInfo,
  1991. sizeof(PerfInfo),
  1992. NULL
  1993. );
  1994. ASSERT(NT_SUCCESS(Status));
  1995. lpBuffer->dwLength = sizeof( *lpBuffer );
  1996. //
  1997. // Capture the number of physical pages as it can change dynamically.
  1998. // If it goes up or down in the middle of this routine, the results may
  1999. // look strange (ie: available > total, etc), but it will quickly
  2000. // right itself.
  2001. //
  2002. NumberOfPhysicalPages = USER_SHARED_DATA->NumberOfPhysicalPages;
  2003. //
  2004. // Determine the memory load. < 100 available pages is 100
  2005. // Otherwise load is ((TotalPhys - AvailPhys) * 100) / TotalPhys
  2006. //
  2007. if (PerfInfo.AvailablePages < 100) {
  2008. lpBuffer->dwMemoryLoad = 100;
  2009. }
  2010. else {
  2011. lpBuffer->dwMemoryLoad =
  2012. ((DWORD)(NumberOfPhysicalPages - PerfInfo.AvailablePages) * 100) /
  2013. NumberOfPhysicalPages;
  2014. }
  2015. Memory64 = (DWORDLONG)NumberOfPhysicalPages * BASE_SYSINFO.PageSize;
  2016. lpBuffer->dwTotalPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
  2017. Memory64 = ((DWORDLONG)PerfInfo.AvailablePages * (DWORDLONG)BASE_SYSINFO.PageSize);
  2018. lpBuffer->dwAvailPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
  2019. if (gpTermsrvAdjustPhyMemLimits) {
  2020. gpTermsrvAdjustPhyMemLimits(&(lpBuffer->dwTotalPhys),
  2021. &(lpBuffer->dwAvailPhys),
  2022. BASE_SYSINFO.PageSize);
  2023. }
  2024. //
  2025. // Zero returned values in case the query process fails.
  2026. //
  2027. RtlZeroMemory (&QuotaLimits, sizeof (QUOTA_LIMITS));
  2028. RtlZeroMemory (&VmCounters, sizeof (VM_COUNTERS));
  2029. Status = NtQueryInformationProcess (NtCurrentProcess(),
  2030. ProcessQuotaLimits,
  2031. &QuotaLimits,
  2032. sizeof(QUOTA_LIMITS),
  2033. NULL );
  2034. Status = NtQueryInformationProcess (NtCurrentProcess(),
  2035. ProcessVmCounters,
  2036. &VmCounters,
  2037. sizeof(VM_COUNTERS),
  2038. NULL );
  2039. //
  2040. // Determine the total page file space with respect to this process.
  2041. //
  2042. Memory64 = __min(PerfInfo.CommitLimit, QuotaLimits.PagefileLimit);
  2043. Memory64 *= BASE_SYSINFO.PageSize;
  2044. lpBuffer->dwTotalPageFile = (SIZE_T)__min(Memory64, MAXULONG_PTR);
  2045. //
  2046. // Determine remaining page file space with respect to this process.
  2047. //
  2048. Memory64 = __min(PerfInfo.CommitLimit - PerfInfo.CommittedPages,
  2049. QuotaLimits.PagefileLimit - VmCounters.PagefileUsage);
  2050. Memory64 *= BASE_SYSINFO.PageSize;
  2051. lpBuffer->dwAvailPageFile = (SIZE_T) __min(Memory64, MAXULONG_PTR);
  2052. lpBuffer->dwTotalVirtual = (BASE_SYSINFO.MaximumUserModeAddress -
  2053. BASE_SYSINFO.MinimumUserModeAddress) + 1;
  2054. lpBuffer->dwAvailVirtual = lpBuffer->dwTotalVirtual - VmCounters.VirtualSize;
  2055. #if !defined(_WIN64)
  2056. //
  2057. // Lie about available memory if application can't handle large (>2GB) addresses
  2058. //
  2059. Peb = NtCurrentPeb();
  2060. NtHeaders = RtlImageNtHeader( Peb->ImageBaseAddress );
  2061. if (NtHeaders && !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) {
  2062. if (lpBuffer->dwTotalPhys > 0x7FFFFFFF) {
  2063. lpBuffer->dwTotalPhys = 0x7FFFFFFF;
  2064. }
  2065. if (lpBuffer->dwAvailPhys > 0x7FFFFFFF) {
  2066. lpBuffer->dwAvailPhys = 0x7FFFFFFF;
  2067. }
  2068. if (lpBuffer->dwTotalVirtual > 0x7FFFFFFF) {
  2069. lpBuffer->dwTotalVirtual = 0x7FFFFFFF;
  2070. }
  2071. if (lpBuffer->dwAvailVirtual > 0x7FFFFFFF) {
  2072. lpBuffer->dwAvailVirtual = 0x7FFFFFFF;
  2073. }
  2074. }
  2075. #endif
  2076. return;
  2077. }
  2078. DWORD
  2079. APIENTRY
  2080. WmipWaitForMultipleObjectsEx(
  2081. DWORD nCount,
  2082. CONST HANDLE *lpHandles,
  2083. BOOL bWaitAll,
  2084. DWORD dwMilliseconds,
  2085. BOOL bAlertable
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. A wait operation on multiple waitable objects (up to
  2090. MAXIMUM_WAIT_OBJECTS) is accomplished with the
  2091. WaitForMultipleObjects function.
  2092. This API can be used to wait on any of the specified objects to
  2093. enter the signaled state, or all of the objects to enter the
  2094. signaled state.
  2095. If the bAlertable parameter is FALSE, the only way the wait
  2096. terminates is because the specified timeout period expires, or
  2097. because the specified objects entered the signaled state. If the
  2098. bAlertable parameter is TRUE, then the wait can return due to any one of
  2099. the above wait termination conditions, or because an I/O completion
  2100. callback terminated the wait early (return value of
  2101. WAIT_IO_COMPLETION).
  2102. Arguments:
  2103. nCount - A count of the number of objects that are to be waited on.
  2104. lpHandles - An array of object handles. Each handle must have
  2105. SYNCHRONIZE access to the associated object.
  2106. bWaitAll - A flag that supplies the wait type. A value of TRUE
  2107. indicates a "wait all". A value of false indicates a "wait
  2108. any".
  2109. dwMilliseconds - A time-out value that specifies the relative time,
  2110. in milliseconds, over which the wait is to be completed. A
  2111. timeout value of 0 specified that the wait is to timeout
  2112. immediately. This allows an application to test an object to
  2113. determine if it is in the signaled state. A timeout value of
  2114. 0xffffffff specifies an infinite timeout period.
  2115. bAlertable - Supplies a flag that controls whether or not the
  2116. wait may terminate early due to an I/O completion callback.
  2117. A value of TRUE allows this API to complete early due to an I/O
  2118. completion callback. A value of FALSE will not allow I/O
  2119. completion callbacks to terminate this call early.
  2120. Return Value:
  2121. WAIT_TIME_OUT - indicates that the wait was terminated due to the
  2122. TimeOut conditions.
  2123. 0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
  2124. object, the object number which satisfied the wait. In the case
  2125. of wait for all objects, the value only indicates that the wait
  2126. was completed successfully.
  2127. 0xffffffff - The wait terminated due to an error. WmipGetLastError may be
  2128. used to get additional error information.
  2129. WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
  2130. indicates, in the case of wait for any object, the object number
  2131. which satisfied the event, and that the object which satisfied
  2132. the event was abandoned. In the case of wait for all objects,
  2133. the value indicates that the wait was completed successfully and
  2134. at least one of the objects was abandoned.
  2135. WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
  2136. completion callbacks.
  2137. --*/
  2138. {
  2139. NTSTATUS Status;
  2140. LARGE_INTEGER TimeOut;
  2141. PLARGE_INTEGER pTimeOut;
  2142. DWORD i;
  2143. LPHANDLE HandleArray;
  2144. HANDLE Handles[ 8 ];
  2145. PPEB Peb;
  2146. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  2147. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  2148. __try {
  2149. if (nCount > 8) {
  2150. HandleArray = (LPHANDLE) RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nCount*sizeof(HANDLE));
  2151. if (HandleArray == NULL) {
  2152. WmipBaseSetLastNTError(STATUS_NO_MEMORY);
  2153. return 0xffffffff;
  2154. }
  2155. } else {
  2156. HandleArray = Handles;
  2157. }
  2158. RtlCopyMemory(HandleArray,(LPVOID)lpHandles,nCount*sizeof(HANDLE));
  2159. Peb = NtCurrentPeb();
  2160. for (i=0;i<nCount;i++) {
  2161. switch( HandleToUlong(HandleArray[i]) ) {
  2162. case STD_INPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardInput;
  2163. break;
  2164. case STD_OUTPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardOutput;
  2165. break;
  2166. case STD_ERROR_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardError;
  2167. break;
  2168. }
  2169. }
  2170. pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
  2171. rewait:
  2172. Status = NtWaitForMultipleObjects(
  2173. (CHAR)nCount,
  2174. HandleArray,
  2175. bWaitAll ? WaitAll : WaitAny,
  2176. (BOOLEAN)bAlertable,
  2177. pTimeOut
  2178. );
  2179. if ( !NT_SUCCESS(Status) ) {
  2180. WmipBaseSetLastNTError(Status);
  2181. Status = (NTSTATUS)0xffffffff;
  2182. }
  2183. else {
  2184. if ( bAlertable && Status == STATUS_ALERTED ) {
  2185. goto rewait;
  2186. }
  2187. }
  2188. if (HandleArray != Handles) {
  2189. RtlFreeHeap(RtlProcessHeap(), 0, HandleArray);
  2190. }
  2191. } __finally {
  2192. RtlDeactivateActivationContextUnsafeFast(&Frame);
  2193. }
  2194. return (DWORD)Status;
  2195. }
  2196. VOID
  2197. WmipSleep(
  2198. DWORD dwMilliseconds
  2199. )
  2200. /*++
  2201. Routine Description:
  2202. The execution of the current thread can be delayed for a specified
  2203. interval of time with the Sleep function.
  2204. The Sleep function causes the current thread to enter a
  2205. waiting state until the specified interval of time has passed.
  2206. Arguments:
  2207. dwMilliseconds - A time-out value that specifies the relative time,
  2208. in milliseconds, over which the wait is to be completed. A
  2209. timeout value of 0 specified that the wait is to timeout
  2210. immediately. This allows an application to test an object to
  2211. determine if it is in the signaled state. A timeout value of -1
  2212. specifies an infinite timeout period.
  2213. Return Value:
  2214. None.
  2215. --*/
  2216. {
  2217. WmipSleepEx(dwMilliseconds,FALSE);
  2218. }
  2219. DWORD
  2220. APIENTRY
  2221. WmipSleepEx(
  2222. DWORD dwMilliseconds,
  2223. BOOL bAlertable
  2224. )
  2225. /*++
  2226. Routine Description:
  2227. The execution of the current thread can be delayed for a specified
  2228. interval of time with the SleepEx function.
  2229. The SleepEx function causes the current thread to enter a waiting
  2230. state until the specified interval of time has passed.
  2231. If the bAlertable parameter is FALSE, the only way the SleepEx
  2232. returns is when the specified time interval has passed. If the
  2233. bAlertable parameter is TRUE, then the SleepEx can return due to the
  2234. expiration of the time interval (return value of 0), or because an
  2235. I/O completion callback terminated the SleepEx early (return value
  2236. of WAIT_IO_COMPLETION).
  2237. Arguments:
  2238. dwMilliseconds - A time-out value that specifies the relative time,
  2239. in milliseconds, over which the wait is to be completed. A
  2240. timeout value of 0 specified that the wait is to timeout
  2241. immediately. A timeout value of -1 specifies an infinite
  2242. timeout period.
  2243. bAlertable - Supplies a flag that controls whether or not the
  2244. SleepEx may terminate early due to an I/O completion callback.
  2245. A value of TRUE allows this API to complete early due to an I/O
  2246. completion callback. A value of FALSE will not allow I/O
  2247. completion callbacks to terminate this call early.
  2248. Return Value:
  2249. 0 - The SleepEx terminated due to expiration of the time interval.
  2250. WAIT_IO_COMPLETION - The SleepEx terminated due to one or more I/O
  2251. completion callbacks.
  2252. --*/
  2253. {
  2254. LARGE_INTEGER TimeOut;
  2255. PLARGE_INTEGER pTimeOut;
  2256. NTSTATUS Status;
  2257. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  2258. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  2259. __try {
  2260. pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
  2261. if (pTimeOut == NULL) {
  2262. //
  2263. // If Sleep( -1 ) then delay for the longest possible integer
  2264. // relative to now.
  2265. //
  2266. TimeOut.LowPart = 0x0;
  2267. TimeOut.HighPart = 0x80000000;
  2268. pTimeOut = &TimeOut;
  2269. }
  2270. rewait:
  2271. Status = NtDelayExecution(
  2272. (BOOLEAN)bAlertable,
  2273. pTimeOut
  2274. );
  2275. if ( bAlertable && Status == STATUS_ALERTED ) {
  2276. goto rewait;
  2277. }
  2278. } __finally {
  2279. RtlDeactivateActivationContextUnsafeFast(&Frame);
  2280. }
  2281. return Status == STATUS_USER_APC ? WAIT_IO_COMPLETION : 0;
  2282. }
  2283. BOOL
  2284. APIENTRY
  2285. WmipSetThreadPriority(
  2286. HANDLE hThread,
  2287. int nPriority
  2288. )
  2289. /*++
  2290. Routine Description:
  2291. The specified thread's priority can be set using SetThreadPriority.
  2292. A thread's priority may be set using SetThreadPriority. This call
  2293. allows the thread's relative execution importance to be communicated
  2294. to the system. The system normally schedules threads according to
  2295. their priority. The system is free to temporarily boost the
  2296. priority of a thread when signifigant events occur (e.g. keyboard
  2297. or mouse input...). Similarly, as a thread runs without blocking,
  2298. the system will decay its priority. The system will never decay the
  2299. priority below the value set by this call.
  2300. In the absence of system originated priority boosts, threads will be
  2301. scheduled in a round-robin fashion at each priority level from
  2302. THREAD_PRIORITY_TIME_CRITICAL to THREAD_PRIORITY_IDLE. Only when there
  2303. are no runnable threads at a higher level, will scheduling of
  2304. threads at a lower level take place.
  2305. All threads initially start at THREAD_PRIORITY_NORMAL.
  2306. If for some reason the thread needs more priority, it can be
  2307. switched to THREAD_PRIORITY_ABOVE_NORMAL or THREAD_PRIORITY_HIGHEST.
  2308. Switching to THREAD_PRIORITY_TIME_CRITICAL should only be done in extreme
  2309. situations. Since these threads are given the highes priority, they
  2310. should only run in short bursts. Running for long durations will
  2311. soak up the systems processing bandwidth starving threads at lower
  2312. levels.
  2313. If a thread needs to do low priority work, or should only run there
  2314. is nothing else to do, its priority should be set to
  2315. THREAD_PRIORITY_BELOW_NORMAL or THREAD_PRIORITY_LOWEST. For extreme
  2316. cases, THREAD_PRIORITY_IDLE can be used.
  2317. Care must be taken when manipulating priorites. If priorities are
  2318. used carelessly (every thread is set to THREAD_PRIORITY_TIME_CRITICAL),
  2319. the effects of priority modifications can produce undesireable
  2320. effects (e.g. starvation, no effect...).
  2321. Arguments:
  2322. hThread - Supplies a handle to the thread whose priority is to be
  2323. set. The handle must have been created with
  2324. THREAD_SET_INFORMATION access.
  2325. nPriority - Supplies the priority value for the thread. The
  2326. following five priority values (ordered from lowest priority to
  2327. highest priority) are allowed.
  2328. nPriority Values:
  2329. THREAD_PRIORITY_IDLE - The thread's priority should be set to
  2330. the lowest possible settable priority.
  2331. THREAD_PRIORITY_LOWEST - The thread's priority should be set to
  2332. the next lowest possible settable priority.
  2333. THREAD_PRIORITY_BELOW_NORMAL - The thread's priority should be
  2334. set to just below normal.
  2335. THREAD_PRIORITY_NORMAL - The thread's priority should be set to
  2336. the normal priority value. This is the value that all
  2337. threads begin execution at.
  2338. THREAD_PRIORITY_ABOVE_NORMAL - The thread's priority should be
  2339. set to just above normal priority.
  2340. THREAD_PRIORITY_HIGHEST - The thread's priority should be set to
  2341. the next highest possible settable priority.
  2342. THREAD_PRIORITY_TIME_CRITICAL - The thread's priority should be set
  2343. to the highest possible settable priority. This priority is
  2344. very likely to interfere with normal operation of the
  2345. system.
  2346. Return Value:
  2347. TRUE - The operation was successful
  2348. FALSE/NULL - The operation failed. Extended error status is available
  2349. using WmipGetLastError.
  2350. --*/
  2351. {
  2352. NTSTATUS Status;
  2353. LONG BasePriority;
  2354. BasePriority = (LONG)nPriority;
  2355. //
  2356. // saturation is indicated by calling with a value of 16 or -16
  2357. //
  2358. if ( BasePriority == THREAD_PRIORITY_TIME_CRITICAL ) {
  2359. BasePriority = ((HIGH_PRIORITY + 1) / 2);
  2360. }
  2361. else if ( BasePriority == THREAD_PRIORITY_IDLE ) {
  2362. BasePriority = -((HIGH_PRIORITY + 1) / 2);
  2363. }
  2364. Status = NtSetInformationThread(
  2365. hThread,
  2366. ThreadBasePriority,
  2367. &BasePriority,
  2368. sizeof(BasePriority)
  2369. );
  2370. if ( !NT_SUCCESS(Status) ) {
  2371. WmipBaseSetLastNTError(Status);
  2372. return FALSE;
  2373. }
  2374. return TRUE;
  2375. }
  2376. BOOL
  2377. WmipDuplicateHandle(
  2378. HANDLE hSourceProcessHandle,
  2379. HANDLE hSourceHandle,
  2380. HANDLE hTargetProcessHandle,
  2381. LPHANDLE lpTargetHandle,
  2382. DWORD dwDesiredAccess,
  2383. BOOL bInheritHandle,
  2384. DWORD dwOptions
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. A duplicate handle can be created with the DuplicateHandle function.
  2389. This is a generic function and operates on the following object
  2390. types:
  2391. - Process Object
  2392. - Thread Object
  2393. - Mutex Object
  2394. - Event Object
  2395. - Semaphore Object
  2396. - File Object
  2397. Please note that Module Objects are not in this list.
  2398. This function requires PROCESS_DUP_ACCESS to both the
  2399. SourceProcessHandle and the TargetProcessHandle. This function is
  2400. used to pass an object handle from one process to another. Once
  2401. this call is complete, the target process needs to be informed of
  2402. the value of the target handle. The target process can then operate
  2403. on the object using this handle value.
  2404. Arguments:
  2405. hSourceProcessHandle - An open handle to the process that contains the
  2406. handle to be duplicated. The handle must have been created with
  2407. PROCESS_DUP_HANDLE access to the process.
  2408. hSourceHandle - An open handle to any object that is valid in the
  2409. context of the source process.
  2410. hTargetProcessHandle - An open handle to the process that is to
  2411. receive the duplicated handle. The handle must have been
  2412. created with PROCESS_DUP_HANDLE access to the process.
  2413. lpTargetHandle - A pointer to a variable which receives the new handle
  2414. that points to the same object as SourceHandle does. This
  2415. handle value is valid in the context of the target process.
  2416. dwDesiredAccess - The access requested to for the new handle. This
  2417. parameter is ignored if the DUPLICATE_SAME_ACCESS option is
  2418. specified.
  2419. bInheritHandle - Supplies a flag that if TRUE, marks the target
  2420. handle as inheritable. If this is the case, then the target
  2421. handle will be inherited to new processes each time the target
  2422. process creates a new process using CreateProcess.
  2423. dwOptions - Specifies optional behaviors for the caller.
  2424. Options Flags:
  2425. DUPLICATE_CLOSE_SOURCE - The SourceHandle will be closed by
  2426. this service prior to returning to the caller. This occurs
  2427. regardless of any error status returned.
  2428. DUPLICATE_SAME_ACCESS - The DesiredAccess parameter is ignored
  2429. and instead the GrantedAccess associated with SourceHandle
  2430. is used as the DesiredAccess when creating the TargetHandle.
  2431. Return Value:
  2432. TRUE - The operation was successful.
  2433. FALSE/NULL - The operation failed. Extended error status is available
  2434. using WmipGetLastError.
  2435. --*/
  2436. {
  2437. NTSTATUS Status;
  2438. PPEB Peb;
  2439. Peb = NtCurrentPeb();
  2440. switch( HandleToUlong(hSourceHandle) ) {
  2441. case STD_INPUT_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardInput;
  2442. break;
  2443. case STD_OUTPUT_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardOutput;
  2444. break;
  2445. case STD_ERROR_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardError;
  2446. break;
  2447. }
  2448. Status = NtDuplicateObject(
  2449. hSourceProcessHandle,
  2450. hSourceHandle,
  2451. hTargetProcessHandle,
  2452. lpTargetHandle,
  2453. (ACCESS_MASK)dwDesiredAccess,
  2454. bInheritHandle ? OBJ_INHERIT : 0,
  2455. dwOptions
  2456. );
  2457. if ( NT_SUCCESS(Status) ) {
  2458. return TRUE;
  2459. }
  2460. else {
  2461. WmipBaseSetLastNTError(Status);
  2462. return FALSE;
  2463. }
  2464. return FALSE;
  2465. }
  2466. UINT
  2467. WmipSetErrorMode(
  2468. UINT uMode
  2469. )
  2470. {
  2471. UINT PreviousMode;
  2472. UINT NewMode;
  2473. PreviousMode = WmipGetErrorMode();
  2474. NewMode = uMode;
  2475. if (NewMode & SEM_FAILCRITICALERRORS ) {
  2476. NewMode &= ~SEM_FAILCRITICALERRORS;
  2477. }
  2478. else {
  2479. NewMode |= SEM_FAILCRITICALERRORS;
  2480. }
  2481. //
  2482. // Once SEM_NOALIGNMENTFAULTEXCEPT has been enabled for a given
  2483. // process, it cannot be disabled via this API.
  2484. //
  2485. NewMode |= (PreviousMode & SEM_NOALIGNMENTFAULTEXCEPT);
  2486. if ( NT_SUCCESS(NtSetInformationProcess(
  2487. NtCurrentProcess(),
  2488. ProcessDefaultHardErrorMode,
  2489. (PVOID) &NewMode,
  2490. sizeof(NewMode)
  2491. ) ) ){
  2492. }
  2493. return( PreviousMode );
  2494. }
  2495. UINT
  2496. WmipGetErrorMode()
  2497. {
  2498. UINT PreviousMode;
  2499. NTSTATUS Status;
  2500. Status = NtQueryInformationProcess(
  2501. NtCurrentProcess(),
  2502. ProcessDefaultHardErrorMode,
  2503. (PVOID) &PreviousMode,
  2504. sizeof(PreviousMode),
  2505. NULL
  2506. );
  2507. if ( !NT_SUCCESS(Status) ) {
  2508. WmipBaseSetLastNTError(Status);
  2509. return 0;
  2510. }
  2511. if (PreviousMode & 1) {
  2512. PreviousMode &= ~SEM_FAILCRITICALERRORS;
  2513. }
  2514. else {
  2515. PreviousMode |= SEM_FAILCRITICALERRORS;
  2516. }
  2517. return PreviousMode;
  2518. }
  2519. ULONG WmipBuildGuidObjectAttributes(
  2520. IN LPGUID Guid,
  2521. OUT POBJECT_ATTRIBUTES ObjectAttributes,
  2522. OUT PUNICODE_STRING GuidString,
  2523. OUT PWCHAR GuidObjectName
  2524. )
  2525. {
  2526. WCHAR GuidChar[37];
  2527. WmipAssert(Guid != NULL);
  2528. //
  2529. // Build up guid name into the ObjectAttributes
  2530. //
  2531. swprintf(GuidChar, L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  2532. Guid->Data1, Guid->Data2,
  2533. Guid->Data3,
  2534. Guid->Data4[0], Guid->Data4[1],
  2535. Guid->Data4[2], Guid->Data4[3],
  2536. Guid->Data4[4], Guid->Data4[5],
  2537. Guid->Data4[6], Guid->Data4[7]);
  2538. WmipAssert(wcslen(GuidChar) == 36);
  2539. wcscpy(GuidObjectName, WmiGuidObjectDirectory);
  2540. wcscat(GuidObjectName, GuidChar);
  2541. RtlInitUnicodeString(GuidString, GuidObjectName);
  2542. memset(ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  2543. ObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
  2544. ObjectAttributes->ObjectName = GuidString;
  2545. return(ERROR_SUCCESS);
  2546. }
  2547. HANDLE
  2548. APIENTRY
  2549. WmipCreateThread(
  2550. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  2551. DWORD dwStackSize,
  2552. LPTHREAD_START_ROUTINE lpStartAddress,
  2553. LPVOID lpParameter,
  2554. DWORD dwCreationFlags,
  2555. LPDWORD lpThreadId
  2556. )
  2557. {
  2558. HANDLE ThreadHandle;
  2559. NTSTATUS st =
  2560. RtlCreateUserThread(
  2561. NtCurrentProcess(), // process handle
  2562. lpThreadAttributes, // security descriptor
  2563. TRUE, // Create suspended?
  2564. 0L, // ZeroBits: default
  2565. dwStackSize, // Max stack size: default
  2566. 0L, // Committed stack size: default
  2567. lpStartAddress, // Function to start in
  2568. lpParameter, // Event the thread signals when ready
  2569. &ThreadHandle, // Thread handle return
  2570. (PCLIENT_ID)lpThreadId // Thread id
  2571. );
  2572. if(NT_SUCCESS(st)){
  2573. st = NtResumeThread(ThreadHandle,NULL);
  2574. }
  2575. if(NT_SUCCESS(st)){
  2576. return ThreadHandle;
  2577. } else {
  2578. return NULL;
  2579. }
  2580. }
  2581. /////////////////////////////////////////////////////////
  2582. /////////////////////////////////////////////////////////
  2583. // TLS FUNCTIONS
  2584. /////////////////////////////////////////////////////////
  2585. /////////////////////////////////////////////////////////
  2586. DWORD
  2587. WmipTlsAlloc(
  2588. VOID
  2589. )
  2590. /*++
  2591. Routine Description:
  2592. A TLS index may be allocated using TlsAllocHelper. Win32 garuntees a
  2593. minimum number of TLS indexes are available in each process. The
  2594. constant TLS_MINIMUM_AVAILABLE defines the minimum number of
  2595. available indexes. This minimum is at least 64 for all Win32
  2596. systems.
  2597. Arguments:
  2598. None.
  2599. Return Value:
  2600. Not-0xffffffff - Returns a TLS index that may be used in a
  2601. subsequent call to TlsFreeHelper, TlsSetValueHelper, or TlsGetValueHelper. The
  2602. storage associated with the index is initialized to NULL.
  2603. 0xffffffff - The operation failed. Extended error status is available
  2604. using GetLastError.
  2605. --*/
  2606. {
  2607. PPEB Peb;
  2608. PTEB Teb;
  2609. DWORD Index;
  2610. Peb = NtCurrentPeb();
  2611. Teb = NtCurrentTeb();
  2612. RtlAcquirePebLock();
  2613. try {
  2614. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
  2615. if ( Index == 0xffffffff ) {
  2616. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsExpansionBitmap,1,0);
  2617. if ( Index == 0xffffffff ) {
  2618. //WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
  2619. }
  2620. else {
  2621. if ( !Teb->TlsExpansionSlots ) {
  2622. Teb->TlsExpansionSlots = RtlAllocateHeap(
  2623. RtlProcessHeap(),
  2624. MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
  2625. TLS_EXPANSION_SLOTS * sizeof(PVOID)
  2626. );
  2627. if ( !Teb->TlsExpansionSlots ) {
  2628. RtlClearBits((PRTL_BITMAP)Peb->TlsExpansionBitmap,Index,1);
  2629. Index = 0xffffffff;
  2630. //WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
  2631. return Index;
  2632. }
  2633. }
  2634. Teb->TlsExpansionSlots[Index] = NULL;
  2635. Index += TLS_MINIMUM_AVAILABLE;
  2636. }
  2637. }
  2638. else {
  2639. Teb->TlsSlots[Index] = NULL;
  2640. }
  2641. }
  2642. finally {
  2643. RtlReleasePebLock();
  2644. }
  2645. #if DBG
  2646. Index |= TLS_MASK;
  2647. #endif
  2648. return Index;
  2649. }
  2650. LPVOID
  2651. WmipTlsGetValue(
  2652. DWORD dwTlsIndex
  2653. )
  2654. /*++
  2655. Routine Description:
  2656. This function is used to retrive the value in the TLS storage
  2657. associated with the specified index.
  2658. If the index is valid this function clears the value returned by
  2659. GetLastError(), and returns the value stored in the TLS slot
  2660. associated with the specified index. Otherwise a value of NULL is
  2661. returned with GetLastError updated appropriately.
  2662. It is expected, that DLLs will use TlsAllocHelper and TlsGetValueHelper as
  2663. follows:
  2664. - Upon DLL initialization, a TLS index will be allocated using
  2665. TlsAllocHelper. The DLL will then allocate some dynamic storage and
  2666. store its address in the TLS slot using TlsSetValueHelper. This
  2667. completes the per thread initialization for the initial thread
  2668. of the process. The TLS index is stored in instance data for
  2669. the DLL.
  2670. - Each time a new thread attaches to the DLL, the DLL will
  2671. allocate some dynamic storage and store its address in the TLS
  2672. slot using TlsSetValueHelper. This completes the per thread
  2673. initialization for the new thread.
  2674. - Each time an initialized thread makes a DLL call requiring the
  2675. TLS, the DLL will call TlsGetValueHelper to get the TLS data for the
  2676. thread.
  2677. Arguments:
  2678. dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. The
  2679. index specifies which TLS slot is to be located. Translating a
  2680. TlsIndex does not prevent a TlsFreeHelper call from proceding.
  2681. Return Value:
  2682. NON-NULL - The function was successful. The value is the data stored
  2683. in the TLS slot associated with the specified index.
  2684. NULL - The operation failed, or the value associated with the
  2685. specified index was NULL. Extended error status is available
  2686. using GetLastError. If this returns non-zero, the index was
  2687. invalid.
  2688. --*/
  2689. {
  2690. PTEB Teb;
  2691. LPVOID *Slot;
  2692. #if DBG
  2693. // See if the Index passed in is from TlsAllocHelper or random goo...
  2694. ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsGetValueHelper\n", (dwTlsIndex & TLS_MASK));
  2695. dwTlsIndex &= ~TLS_MASK;
  2696. #endif
  2697. Teb = NtCurrentTeb();
  2698. if ( dwTlsIndex < TLS_MINIMUM_AVAILABLE ) {
  2699. Slot = &Teb->TlsSlots[dwTlsIndex];
  2700. Teb->LastErrorValue = 0;
  2701. return *Slot;
  2702. }
  2703. else {
  2704. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE+TLS_EXPANSION_SLOTS ) {
  2705. WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
  2706. return NULL;
  2707. }
  2708. else {
  2709. Teb->LastErrorValue = 0;
  2710. if ( Teb->TlsExpansionSlots ) {
  2711. return Teb->TlsExpansionSlots[dwTlsIndex-TLS_MINIMUM_AVAILABLE];
  2712. }
  2713. else {
  2714. return NULL;
  2715. }
  2716. }
  2717. }
  2718. }
  2719. BOOL
  2720. WmipTlsSetValue(
  2721. DWORD dwTlsIndex,
  2722. LPVOID lpTlsValue
  2723. )
  2724. /*++
  2725. Routine Description:
  2726. This function is used to store a value in the TLS storage associated
  2727. with the specified index.
  2728. If the index is valid this function stores the value and returns
  2729. TRUE. Otherwise a value of FALSE is returned.
  2730. It is expected, that DLLs will use TlsAllocHelper and TlsSetValueHelper as
  2731. follows:
  2732. - Upon DLL initialization, a TLS index will be allocated using
  2733. TlsAllocHelper. The DLL will then allocate some dynamic storage and
  2734. store its address in the TLS slot using TlsSetValueHelper. This
  2735. completes the per thread initialization for the initial thread
  2736. of the process. The TLS index is stored in instance data for
  2737. the DLL.
  2738. - Each time a new thread attaches to the DLL, the DLL will
  2739. allocate some dynamic storage and store its address in the TLS
  2740. slot using TlsSetValueHelper. This completes the per thread
  2741. initialization for the new thread.
  2742. - Each time an initialized thread makes a DLL call requiring the
  2743. TLS, the DLL will call TlsGetValueHelper to get the TLS data for the
  2744. thread.
  2745. Arguments:
  2746. dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. The
  2747. index specifies which TLS slot is to be located. Translating a
  2748. TlsIndex does not prevent a TlsFreeHelper call from proceding.
  2749. lpTlsValue - Supplies the value to be stored in the TLS Slot.
  2750. Return Value:
  2751. TRUE - The function was successful. The value lpTlsValue was
  2752. stored.
  2753. FALSE - The operation failed. Extended error status is available
  2754. using GetLastError.
  2755. --*/
  2756. {
  2757. PTEB Teb;
  2758. #if DBG
  2759. // See if the Index passed in is from TlsAllocHelper or random goo...
  2760. ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsSetValueHelper\n", (dwTlsIndex & TLS_MASK));
  2761. dwTlsIndex &= ~TLS_MASK;
  2762. #endif
  2763. Teb = NtCurrentTeb();
  2764. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
  2765. dwTlsIndex -= TLS_MINIMUM_AVAILABLE;
  2766. if ( dwTlsIndex < TLS_EXPANSION_SLOTS ) {
  2767. if ( !Teb->TlsExpansionSlots ) {
  2768. RtlAcquirePebLock();
  2769. if ( !Teb->TlsExpansionSlots ) {
  2770. Teb->TlsExpansionSlots = RtlAllocateHeap(
  2771. RtlProcessHeap(),
  2772. MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
  2773. TLS_EXPANSION_SLOTS * sizeof(PVOID)
  2774. );
  2775. if ( !Teb->TlsExpansionSlots ) {
  2776. RtlReleasePebLock();
  2777. WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
  2778. return FALSE;
  2779. }
  2780. }
  2781. RtlReleasePebLock();
  2782. }
  2783. Teb->TlsExpansionSlots[dwTlsIndex] = lpTlsValue;
  2784. }
  2785. else {
  2786. WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
  2787. return FALSE;
  2788. }
  2789. }
  2790. else {
  2791. Teb->TlsSlots[dwTlsIndex] = lpTlsValue;
  2792. }
  2793. return TRUE;
  2794. }
  2795. BOOL
  2796. WmipTlsFree(
  2797. DWORD dwTlsIndex
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. A valid TLS index may be free'd using TlsFreeHelper.
  2802. Arguments:
  2803. dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. If the
  2804. index is a valid index, it is released by this call and is made
  2805. available for reuse. DLLs should be carefull to release any
  2806. per-thread data pointed to by all of their threads TLS slots
  2807. before calling this function. It is expected that DLLs will
  2808. only call this function (if at ALL) during their process detach
  2809. routine.
  2810. Return Value:
  2811. TRUE - The operation was successful. Calling TlsTranslateIndex with
  2812. this index will fail. TlsAllocHelper is free to reallocate this
  2813. index.
  2814. FALSE - The operation failed. Extended error status is available
  2815. using GetLastError.
  2816. --*/
  2817. {
  2818. PPEB Peb;
  2819. BOOLEAN ValidIndex;
  2820. PRTL_BITMAP TlsBitmap;
  2821. NTSTATUS Status;
  2822. DWORD Index2;
  2823. #if DBG
  2824. // See if the Index passed in is from TlsAllocHelper or random goo...
  2825. ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsFreeHelper\n", (dwTlsIndex & TLS_MASK));
  2826. dwTlsIndex &= ~TLS_MASK;
  2827. #endif
  2828. Peb = NtCurrentPeb();
  2829. RtlAcquirePebLock();
  2830. try {
  2831. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
  2832. Index2 = dwTlsIndex - TLS_MINIMUM_AVAILABLE;
  2833. if ( Index2 >= TLS_EXPANSION_SLOTS ) {
  2834. ValidIndex = FALSE;
  2835. }
  2836. else {
  2837. TlsBitmap = (PRTL_BITMAP)Peb->TlsExpansionBitmap;
  2838. ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
  2839. }
  2840. }
  2841. else {
  2842. TlsBitmap = (PRTL_BITMAP)Peb->TlsBitmap;
  2843. Index2 = dwTlsIndex;
  2844. ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
  2845. }
  2846. if ( ValidIndex ) {
  2847. Status = NtSetInformationThread(
  2848. NtCurrentThread(),
  2849. ThreadZeroTlsCell,
  2850. &dwTlsIndex,
  2851. sizeof(dwTlsIndex)
  2852. );
  2853. if ( !NT_SUCCESS(Status) ) {
  2854. WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
  2855. return FALSE;
  2856. }
  2857. RtlClearBits(TlsBitmap,Index2,1);
  2858. }
  2859. else {
  2860. WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
  2861. }
  2862. }
  2863. finally {
  2864. RtlReleasePebLock();
  2865. }
  2866. return ValidIndex;
  2867. }
  2868. BOOL
  2869. WmipBasep8BitStringToDynamicUnicodeString(
  2870. OUT PUNICODE_STRING UnicodeString,
  2871. IN LPCSTR lpSourceString
  2872. )
  2873. /*++
  2874. Routine Description:
  2875. Captures and converts a 8-bit (OEM or ANSI) string into a heap-allocated
  2876. UNICODE string
  2877. Arguments:
  2878. UnicodeString - location where UNICODE_STRING is stored
  2879. lpSourceString - string in OEM or ANSI
  2880. Return Value:
  2881. TRUE if string is correctly stored, FALSE if an error occurred. In the
  2882. error case, the last error is correctly set.
  2883. --*/
  2884. {
  2885. ANSI_STRING AnsiString;
  2886. NTSTATUS Status;
  2887. //
  2888. // Convert input into dynamic unicode string
  2889. //
  2890. RtlInitString( &AnsiString, lpSourceString );
  2891. Status = RtlAnsiStringToUnicodeString( UnicodeString, &AnsiString, TRUE );
  2892. //
  2893. // If we couldn't do this, fail
  2894. //
  2895. if (!NT_SUCCESS( Status )){
  2896. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  2897. WmipSetLastError( ERROR_FILENAME_EXCED_RANGE );
  2898. } else {
  2899. WmipBaseSetLastNTError( Status );
  2900. }
  2901. return FALSE;
  2902. }
  2903. return TRUE;
  2904. }
  2905. DWORD
  2906. APIENTRY
  2907. WmipGetFullPathNameA(
  2908. LPCSTR lpFileName,
  2909. DWORD nBufferLength,
  2910. LPSTR lpBuffer,
  2911. LPSTR *lpFilePart
  2912. )
  2913. /*++
  2914. Routine Description:
  2915. ANSI thunk to GetFullPathNameW
  2916. --*/
  2917. {
  2918. NTSTATUS Status;
  2919. ULONG UnicodeLength;
  2920. UNICODE_STRING UnicodeString;
  2921. UNICODE_STRING UnicodeResult;
  2922. ANSI_STRING AnsiResult;
  2923. PWSTR Ubuff;
  2924. PWSTR FilePart;
  2925. PWSTR *FilePartPtr;
  2926. INT PrefixLength = 0;
  2927. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  2928. FilePartPtr = &FilePart;
  2929. }
  2930. else {
  2931. FilePartPtr = NULL;
  2932. }
  2933. if (!WmipBasep8BitStringToDynamicUnicodeString( &UnicodeString, lpFileName )) {
  2934. return 0;
  2935. }
  2936. Ubuff = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (MAX_PATH<<1) + sizeof(UNICODE_NULL));
  2937. if ( !Ubuff ) {
  2938. RtlFreeUnicodeString(&UnicodeString);
  2939. WmipBaseSetLastNTError(STATUS_NO_MEMORY);
  2940. return 0;
  2941. }
  2942. UnicodeLength = RtlGetFullPathName_U(
  2943. UnicodeString.Buffer,
  2944. (MAX_PATH<<1),
  2945. Ubuff,
  2946. FilePartPtr
  2947. );
  2948. //
  2949. // UnicodeLength contains the byte count of unicode string.
  2950. // Original code does "UnicodeLength / sizeof(WCHAR)" to get
  2951. // the size of corresponding ansi string.
  2952. // This is correct in SBCS environment. However in DBCS environment,
  2953. // it's definitely WRONG.
  2954. //
  2955. if ( UnicodeLength <= ((MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL))) ) {
  2956. Status = RtlUnicodeToMultiByteSize(&UnicodeLength, Ubuff, UnicodeLength);
  2957. //
  2958. // At this point, UnicodeLength variable contains
  2959. // Ansi based byte length.
  2960. //
  2961. if ( NT_SUCCESS(Status) ) {
  2962. if ( UnicodeLength && ARGUMENT_PRESENT(lpFilePart) && FilePart != NULL ) {
  2963. INT UnicodePrefixLength;
  2964. UnicodePrefixLength = (INT)(FilePart - Ubuff) * sizeof(WCHAR);
  2965. Status = RtlUnicodeToMultiByteSize( &PrefixLength,
  2966. Ubuff,
  2967. UnicodePrefixLength );
  2968. //
  2969. // At this point, PrefixLength variable contains
  2970. // Ansi based byte length.
  2971. //
  2972. if ( !NT_SUCCESS(Status) ) {
  2973. WmipBaseSetLastNTError(Status);
  2974. UnicodeLength = 0;
  2975. }
  2976. }
  2977. } else {
  2978. WmipBaseSetLastNTError(Status);
  2979. UnicodeLength = 0;
  2980. }
  2981. } else {
  2982. //
  2983. // we exceed the MAX_PATH limit. we should log the error and
  2984. // return zero. however US code returns the byte count of
  2985. // buffer required and doesn't log any error.
  2986. //
  2987. UnicodeLength = 0;
  2988. }
  2989. if ( UnicodeLength && UnicodeLength < nBufferLength ) {
  2990. RtlInitUnicodeString(&UnicodeResult,Ubuff);
  2991. Status = BasepUnicodeStringTo8BitString(&AnsiResult,&UnicodeResult,TRUE);
  2992. if ( NT_SUCCESS(Status) ) {
  2993. RtlMoveMemory(lpBuffer,AnsiResult.Buffer,UnicodeLength+1);
  2994. RtlFreeAnsiString(&AnsiResult);
  2995. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  2996. if ( FilePart == NULL ) {
  2997. *lpFilePart = NULL;
  2998. }
  2999. else {
  3000. *lpFilePart = lpBuffer + PrefixLength;
  3001. }
  3002. }
  3003. }
  3004. else {
  3005. WmipBaseSetLastNTError(Status);
  3006. UnicodeLength = 0;
  3007. }
  3008. }
  3009. else {
  3010. if ( UnicodeLength ) {
  3011. UnicodeLength++;
  3012. }
  3013. }
  3014. RtlFreeUnicodeString(&UnicodeString);
  3015. RtlFreeHeap(RtlProcessHeap(), 0,Ubuff);
  3016. return (DWORD)UnicodeLength;
  3017. }