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

1156 lines
27 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. utility.c
  5. Abstract:
  6. This file contains utility functions that are
  7. used by all other files in this project.
  8. Author:
  9. Wesley Witt [wesw] 1-March-2000
  10. Revision History:
  11. --*/
  12. #include <precomp.h>
  13. INT
  14. Help(
  15. IN INT argc,
  16. IN PWSTR argv[]
  17. )
  18. /*++
  19. Routine Description:
  20. This routine lists out the various command supported by the
  21. tool.
  22. Arguments:
  23. None
  24. Return Value:
  25. None
  26. --*/
  27. {
  28. DisplayMsg( MSG_USAGE );
  29. return EXIT_CODE_SUCCESS;
  30. }
  31. VOID
  32. OutputMessage(
  33. LPWSTR Message
  34. )
  35. {
  36. OutputMessageLength( Message, wcslen( Message ));
  37. }
  38. VOID
  39. OutputMessageLength(
  40. LPWSTR Message,
  41. int Length
  42. )
  43. {
  44. DWORD dwBytesWritten;
  45. DWORD fdwMode;
  46. HANDLE outHandle = GetStdHandle( STD_OUTPUT_HANDLE );
  47. //
  48. // If we have a char mode output handle and that handle
  49. // looks like a console handle, then use unicode
  50. // output
  51. //
  52. if (GetFileType( outHandle ) == FILE_TYPE_CHAR
  53. && GetConsoleMode( outHandle, &fdwMode )) {
  54. WriteConsole( outHandle,
  55. Message,
  56. Length,
  57. &dwBytesWritten,
  58. 0 );
  59. } else {
  60. //
  61. // Output device can't handle Unicode. The best we can do is
  62. // convert to multibyte byte strings and just write it out.
  63. // Yes, some codepoints won't make it out, but the convention
  64. // is that file output is MBCS
  65. //
  66. int charCount =
  67. WideCharToMultiByte( GetConsoleOutputCP( ),
  68. 0,
  69. Message,
  70. Length,
  71. 0,
  72. 0,
  73. 0,
  74. 0 );
  75. PCHAR szaStr = (PCHAR) malloc( charCount + 1 );
  76. if (szaStr != NULL) {
  77. WideCharToMultiByte( GetConsoleOutputCP( ), 0, Message, Length, szaStr, charCount + 1, 0, 0);
  78. WriteFile( outHandle, szaStr, charCount, &dwBytesWritten, 0 );
  79. free( szaStr );
  80. }
  81. }
  82. }
  83. HANDLE NtDllHandle = INVALID_HANDLE_VALUE;
  84. VOID
  85. DisplayErrorMsg(
  86. LONG msgId,
  87. ...
  88. )
  89. /*++
  90. Routine Description:
  91. This routine displays the error message correspnding to
  92. the error indicated by msgId.
  93. Arguments:
  94. msgId - the errorId. This is either the Win32 status code or the message ID.
  95. Return Value:
  96. None
  97. --*/
  98. {
  99. va_list args;
  100. LPWSTR lpMsgBuf;
  101. va_start( args, msgId );
  102. if (FormatMessage(
  103. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  104. NULL,
  105. MSG_ERROR,
  106. 0,
  107. (LPWSTR) &lpMsgBuf,
  108. 0,
  109. NULL
  110. ))
  111. {
  112. OutputMessage( lpMsgBuf );
  113. LocalFree( lpMsgBuf );
  114. }
  115. if (FormatMessage(
  116. (msgId >= MSG_FIRST_MESSAGE_ID ? FORMAT_MESSAGE_FROM_HMODULE :
  117. FORMAT_MESSAGE_FROM_SYSTEM)
  118. | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  119. NULL,
  120. msgId,
  121. 0,
  122. (LPWSTR) &lpMsgBuf,
  123. 0,
  124. &args
  125. ))
  126. {
  127. OutputMessage( L" " );
  128. OutputMessage( lpMsgBuf );
  129. OutputMessage( L"\r\n" );
  130. LocalFree( lpMsgBuf );
  131. } else {
  132. if (NtDllHandle == INVALID_HANDLE_VALUE) {
  133. NtDllHandle = GetModuleHandle( L"NTDLL" );
  134. }
  135. if (FormatMessage(
  136. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  137. (LPVOID)NtDllHandle,
  138. msgId,
  139. 0,
  140. (LPWSTR) &lpMsgBuf,
  141. 0,
  142. &args))
  143. {
  144. OutputMessage( L" " );
  145. OutputMessage( lpMsgBuf );
  146. OutputMessage( L"\r\n" );
  147. LocalFree( lpMsgBuf );
  148. } else {
  149. wprintf( L"Unable to format message for id %x - %x\n", msgId, GetLastError( ));
  150. }
  151. }
  152. va_end( args );
  153. }
  154. VOID
  155. DisplayMsg(
  156. LONG msgId,
  157. ...
  158. )
  159. /*++
  160. Routine Description:
  161. This routine displays the error message correspnding to
  162. the error indicated by msgId.
  163. Arguments:
  164. msgId - the errorId. This is either the Win32 status or the
  165. message Id
  166. Return Value:
  167. None
  168. --*/
  169. {
  170. va_list args;
  171. LPWSTR lpMsgBuf;
  172. va_start( args, msgId );
  173. if (FormatMessage(
  174. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  175. NULL,
  176. msgId,
  177. 0,
  178. (LPWSTR) &lpMsgBuf,
  179. 0,
  180. &args
  181. ))
  182. {
  183. OutputMessage( lpMsgBuf );
  184. LocalFree( lpMsgBuf );
  185. } else {
  186. if (NtDllHandle == INVALID_HANDLE_VALUE) {
  187. NtDllHandle = GetModuleHandle( L"NTDLL" );
  188. }
  189. if (FormatMessage(
  190. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  191. (LPVOID)NtDllHandle,
  192. msgId,
  193. 0,
  194. (LPWSTR) &lpMsgBuf,
  195. 0,
  196. &args))
  197. {
  198. OutputMessage( L" " );
  199. OutputMessage( lpMsgBuf );
  200. OutputMessage( L"\r\n" );
  201. LocalFree( lpMsgBuf );
  202. } else {
  203. wprintf( L"Unable to format message for id %x - %x\n", msgId, GetLastError( ));
  204. }
  205. }
  206. va_end( args );
  207. }
  208. VOID
  209. DisplayError(
  210. void
  211. )
  212. /*++
  213. Routine Description:
  214. This routine displays the last error message.
  215. Arguments:
  216. None
  217. Return Value:
  218. None
  219. --*/
  220. {
  221. DisplayErrorMsg( GetLastError() );
  222. }
  223. BOOL
  224. EnablePrivilege(
  225. LPCWSTR SePrivilege
  226. )
  227. {
  228. HANDLE Token;
  229. PTOKEN_PRIVILEGES NewPrivileges = NULL;
  230. BYTE OldPriv[1024];
  231. PBYTE pbOldPriv = NULL;
  232. ULONG cbNeeded;
  233. BOOL b = TRUE;
  234. LUID LuidPrivilege;
  235. //
  236. // Make sure we have access to adjust and to get the old
  237. // token privileges
  238. //
  239. if (!OpenProcessToken( GetCurrentProcess(),
  240. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  241. &Token))
  242. {
  243. return( FALSE );
  244. }
  245. try {
  246. cbNeeded = 0;
  247. //
  248. // Initialize the privilege adjustment structure
  249. //
  250. LookupPrivilegeValue(NULL, SePrivilege, &LuidPrivilege );
  251. NewPrivileges = (PTOKEN_PRIVILEGES)
  252. calloc(1,sizeof(TOKEN_PRIVILEGES) +
  253. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  254. if (NewPrivileges == NULL) {
  255. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  256. b = FALSE;
  257. leave;
  258. }
  259. NewPrivileges->PrivilegeCount = 1;
  260. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  261. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  262. //
  263. // Enable the privilege
  264. //
  265. b = AdjustTokenPrivileges( Token,
  266. FALSE,
  267. NewPrivileges,
  268. 1024,
  269. (PTOKEN_PRIVILEGES)OldPriv,
  270. &cbNeeded );
  271. if (!b) {
  272. //
  273. // If the stack was too small to hold the privileges
  274. // then allocate off the heap
  275. //
  276. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  277. pbOldPriv = (PBYTE)calloc( 1, cbNeeded );
  278. if (pbOldPriv == NULL) {
  279. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  280. leave;
  281. }
  282. b = AdjustTokenPrivileges( Token,
  283. FALSE,
  284. NewPrivileges,
  285. cbNeeded,
  286. (PTOKEN_PRIVILEGES)pbOldPriv,
  287. &cbNeeded );
  288. }
  289. }
  290. } finally {
  291. CloseHandle( Token );
  292. free( NewPrivileges );
  293. free( pbOldPriv );
  294. }
  295. return( b );
  296. }
  297. BOOL
  298. IsUserAdmin(
  299. VOID
  300. )
  301. /*++
  302. Routine Description:
  303. This routine returns TRUE if the caller's process is a
  304. member of the Administrators local group.
  305. Caller is NOT expected to be impersonating anyone and IS
  306. expected to be able to open their own process and process
  307. token.
  308. Arguments:
  309. None.
  310. Return Value:
  311. TRUE - Caller has Administrators local group.
  312. FALSE - Caller does not have Administrators local group.
  313. --*/
  314. {
  315. BOOL b = FALSE;
  316. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  317. PSID AdministratorsGroup = NULL;
  318. //
  319. // Get SID for Administrators group
  320. //
  321. b = AllocateAndInitializeSid(
  322. &NtAuthority,
  323. 2,
  324. SECURITY_BUILTIN_DOMAIN_RID,
  325. DOMAIN_ALIAS_RID_ADMINS,
  326. 0, 0, 0, 0, 0, 0,
  327. &AdministratorsGroup
  328. );
  329. //
  330. // If we got the sid, check to see if it's enabled in the
  331. // current token
  332. //
  333. if (b) {
  334. if (!CheckTokenMembership( NULL, AdministratorsGroup, &b )) {
  335. b = FALSE;
  336. }
  337. FreeSid( AdministratorsGroup );
  338. }
  339. return(b);
  340. }
  341. BOOL
  342. IsVolumeLocalNTFS(
  343. WCHAR DriveLetter
  344. )
  345. {
  346. BOOL b;
  347. ULONG i;
  348. WCHAR DosName[16];
  349. WCHAR PhysicalName[MAX_PATH];
  350. DosName[0] = DriveLetter;
  351. DosName[1] = L':';
  352. DosName[2] = L'\\';
  353. DosName[3] = L'\0';
  354. switch (GetDriveType( DosName )) {
  355. case DRIVE_UNKNOWN:
  356. case DRIVE_REMOTE:
  357. return FALSE;
  358. }
  359. b = GetVolumeInformation(
  360. DosName,
  361. NULL,
  362. 0,
  363. NULL,
  364. &i,
  365. &i,
  366. PhysicalName,
  367. sizeof(PhysicalName)/sizeof(WCHAR)
  368. );
  369. if (!b ) {
  370. DisplayError();
  371. return FALSE;
  372. }
  373. if (_wcsicmp( PhysicalName, L"NTFS" ) != 0) {
  374. return FALSE;
  375. }
  376. return TRUE;
  377. }
  378. BOOL
  379. IsVolumeNTFS(
  380. PWCHAR path
  381. )
  382. {
  383. //
  384. // Scan backwards through the path looking for \ and trying at each level until we
  385. // get to the root. We'll terminate it there and pass it to GetVolumeInformation
  386. //
  387. PWCHAR LastBackSlash = path + wcslen( path );
  388. WCHAR c;
  389. BOOL b;
  390. ULONG i;
  391. WCHAR PhysicalName[MAX_PATH];
  392. while (TRUE) {
  393. while (TRUE) {
  394. if (LastBackSlash < path) {
  395. DisplayError();
  396. return FALSE;
  397. }
  398. if (*LastBackSlash == L'\\') {
  399. break;
  400. }
  401. LastBackSlash--;
  402. }
  403. c = LastBackSlash[1];
  404. LastBackSlash[1] = L'\0';
  405. b = GetVolumeInformation(
  406. path,
  407. NULL,
  408. 0,
  409. NULL,
  410. &i,
  411. &i,
  412. PhysicalName,
  413. sizeof(PhysicalName)/sizeof(WCHAR)
  414. );
  415. LastBackSlash[1] = c;
  416. LastBackSlash--;
  417. if ( b ) {
  418. return _wcsicmp( PhysicalName, L"NTFS" ) == 0;
  419. }
  420. }
  421. }
  422. BOOL
  423. IsVolumeLocal(
  424. WCHAR DriveLetter
  425. )
  426. {
  427. BOOL b;
  428. ULONG i;
  429. WCHAR DosName[16];
  430. WCHAR PhysicalName[MAX_PATH];
  431. DosName[0] = DriveLetter;
  432. DosName[1] = L':';
  433. DosName[2] = L'\\';
  434. DosName[3] = L'\0';
  435. switch (GetDriveType( DosName )) {
  436. case DRIVE_UNKNOWN:
  437. case DRIVE_REMOTE:
  438. return FALSE;
  439. }
  440. return TRUE;
  441. }
  442. PWSTR
  443. GetFullPath(
  444. IN PWSTR FilenameIn
  445. )
  446. {
  447. WCHAR Filename[MAX_PATH];
  448. PWSTR FilePart;
  449. if (!GetFullPathName( FilenameIn, sizeof(Filename)/sizeof(WCHAR), Filename, &FilePart )) {
  450. return NULL;
  451. }
  452. return _wcsdup( Filename );
  453. }
  454. //
  455. // I64-width number formatting is broken in FormatMessage. We have to convert the numbers
  456. // ourselves and then display them as strings. Rather than declaring buffers on the stack,
  457. // we will allocate space dynamically, and format the text into that spot.
  458. //
  459. // While *TECHNICALLY* this is a leak, the utility quickly exits.
  460. //
  461. #define NUMERICBUFFERLENGTH 40
  462. PWSTR
  463. QuadToDecimalText(
  464. ULONGLONG Value
  465. )
  466. {
  467. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  468. if (Buffer == NULL) {
  469. exit( 1);
  470. }
  471. swprintf( Buffer, L"%I64u", Value );
  472. return Buffer;
  473. }
  474. PWSTR
  475. QuadToHexText(
  476. ULONGLONG Value
  477. )
  478. {
  479. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  480. if (Buffer == NULL) {
  481. exit( 1);
  482. }
  483. swprintf( Buffer, L"%I64x", Value );
  484. return Buffer;
  485. }
  486. PWSTR
  487. QuadToPaddedHexText(
  488. ULONGLONG Value
  489. )
  490. {
  491. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  492. if (Buffer == NULL) {
  493. exit( 1);
  494. }
  495. swprintf( Buffer, L"%016I64x", Value );
  496. return Buffer;
  497. }
  498. #if TRUE
  499. /***
  500. *wcstoq, wcstouq(nptr,endptr,ibase) - Convert ascii string to un/signed __int64.
  501. *
  502. *Purpose:
  503. * Convert an ascii string to a 64-bit __int64 value. The base
  504. * used for the caculations is supplied by the caller. The base
  505. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  506. * ascii string must be examined to determine the base of the
  507. * number:
  508. * (a) First wchar_t = '0', second wchar_t = 'x' or 'X',
  509. * use base 16.
  510. * (b) First wchar_t = '0', use base 8
  511. * (c) First wchar_t in range '1' - '9', use base 10.
  512. *
  513. * If the 'endptr' value is non-NULL, then wcstoq/wcstouq places
  514. * a pointer to the terminating character in this value.
  515. * See ANSI standard for details
  516. *
  517. *Entry:
  518. * nptr == NEAR/FAR pointer to the start of string.
  519. * endptr == NEAR/FAR pointer to the end of the string.
  520. * ibase == integer base to use for the calculations.
  521. *
  522. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  523. *
  524. *Exit:
  525. * Good return:
  526. * result
  527. *
  528. * Overflow return:
  529. * wcstoq -- _I64_MAX or _I64_MIN
  530. * wcstouq -- _UI64_MAX
  531. * wcstoq/wcstouq -- errno == ERANGE
  532. *
  533. * No digits or bad base return:
  534. * 0
  535. * endptr = nptr*
  536. *
  537. *Exceptions:
  538. * None.
  539. *******************************************************************************/
  540. /* flag values */
  541. #define FL_UNSIGNED 1 /* wcstouq called */
  542. #define FL_NEG 2 /* negative sign found */
  543. #define FL_OVERFLOW 4 /* overflow occured */
  544. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  545. static unsigned __int64 __cdecl wcstoxq (
  546. const wchar_t *nptr,
  547. const wchar_t **endptr,
  548. int ibase,
  549. int flags
  550. )
  551. {
  552. const wchar_t *p;
  553. wchar_t c;
  554. unsigned __int64 number;
  555. unsigned digval;
  556. unsigned __int64 maxval;
  557. p = nptr; /* p is our scanning pointer */
  558. number = 0; /* start with zero */
  559. c = *p++; /* read wchar_t */
  560. while ( iswspace(c) )
  561. c = *p++; /* skip whitespace */
  562. if (c == '-') {
  563. flags |= FL_NEG; /* remember minus sign */
  564. c = *p++;
  565. }
  566. else if (c == '+')
  567. c = *p++; /* skip sign */
  568. if (ibase < 0 || ibase == 1 || ibase > 36) {
  569. /* bad base! */
  570. if (endptr)
  571. /* store beginning of string in endptr */
  572. *endptr = nptr;
  573. return 0L; /* return 0 */
  574. }
  575. else if (ibase == 0) {
  576. /* determine base free-lance, based on first two chars of
  577. string */
  578. if (c != '0')
  579. ibase = 10;
  580. else if (*p == 'x' || *p == 'X')
  581. ibase = 16;
  582. else
  583. ibase = 8;
  584. }
  585. if (ibase == 16) {
  586. /* we might have 0x in front of number; remove if there */
  587. if (c == '0' && (*p == 'x' || *p == 'X')) {
  588. ++p;
  589. c = *p++; /* advance past prefix */
  590. }
  591. }
  592. /* if our number exceeds this, we will overflow on multiply */
  593. maxval = _UI64_MAX / ibase;
  594. for (;;) { /* exit in middle of loop */
  595. /* convert c to value */
  596. if ( isdigit((unsigned)c) )
  597. digval = c - '0';
  598. else if ( isalpha((unsigned)c) )
  599. digval = toupper(c) - 'A' + 10;
  600. else
  601. break;
  602. if (digval >= (unsigned)ibase)
  603. break; /* exit loop if bad digit found */
  604. /* record the fact we have read one digit */
  605. flags |= FL_READDIGIT;
  606. /* we now need to compute number = number * base + digval,
  607. but we need to know if overflow occured. This requires
  608. a tricky pre-check. */
  609. if (number < maxval || (number == maxval &&
  610. (unsigned __int64)digval <= _UI64_MAX % ibase)) {
  611. /* we won't overflow, go ahead and multiply */
  612. number = number * ibase + digval;
  613. }
  614. else {
  615. /* we would have overflowed -- set the overflow flag */
  616. flags |= FL_OVERFLOW;
  617. }
  618. c = *p++; /* read next digit */
  619. }
  620. --p; /* point to place that stopped scan */
  621. if (!(flags & FL_READDIGIT)) {
  622. /* no number there; return 0 and point to beginning of
  623. string */
  624. /* store beginning of string in endptr later on */
  625. p = nptr;
  626. number = 0L; /* return 0 */
  627. }
  628. else if ((flags & FL_OVERFLOW) ||
  629. (!(flags & FL_UNSIGNED) &&
  630. (number & ((unsigned __int64)_I64_MAX+1)))) {
  631. /* overflow occurred or signed overflow occurred */
  632. errno = ERANGE;
  633. if (flags & FL_UNSIGNED)
  634. number = _UI64_MAX;
  635. else
  636. /* set error code, will be negated if necc. */
  637. number = _I64_MAX;
  638. flags &= ~FL_NEG;
  639. }
  640. else if ((flags & FL_UNSIGNED) && (flags & FL_NEG)) {
  641. // Disallow a negative sign if we're reading an unsigned
  642. number = 0L;
  643. p = nptr;
  644. }
  645. if (endptr != NULL)
  646. /* store pointer to wchar_t that stopped the scan */
  647. *endptr = p;
  648. if (flags & FL_NEG)
  649. /* negate result if there was a neg sign */
  650. number = (unsigned __int64)(-(__int64)number);
  651. return number; /* done. */
  652. }
  653. __int64 __cdecl My_wcstoi64(
  654. const wchar_t *nptr,
  655. wchar_t **endptr,
  656. int ibase
  657. )
  658. {
  659. return (__int64) wcstoxq(nptr, endptr, ibase, 0);
  660. }
  661. unsigned __int64 __cdecl My_wcstoui64 (
  662. const wchar_t *nptr,
  663. wchar_t **endptr,
  664. int ibase
  665. )
  666. {
  667. return wcstoxq(nptr, endptr, ibase, FL_UNSIGNED);
  668. }
  669. /***
  670. *wcstol, wcstoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
  671. * int.
  672. *
  673. *Purpose:
  674. * Convert an ascii string to a long 32-bit value. The base
  675. * used for the caculations is supplied by the caller. The base
  676. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  677. * ascii string must be examined to determine the base of the
  678. * number:
  679. * (a) First char = '0', second char = 'x' or 'X',
  680. * use base 16.
  681. * (b) First char = '0', use base 8
  682. * (c) First char in range '1' - '9', use base 10.
  683. *
  684. * If the 'endptr' value is non-NULL, then wcstol/wcstoul places
  685. * a pointer to the terminating character in this value.
  686. * See ANSI standard for details
  687. *
  688. *Entry:
  689. * nptr == NEAR/FAR pointer to the start of string.
  690. * endptr == NEAR/FAR pointer to the end of the string.
  691. * ibase == integer base to use for the calculations.
  692. *
  693. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  694. *
  695. *Exit:
  696. * Good return:
  697. * result
  698. *
  699. * Overflow return:
  700. * wcstol -- LONG_MAX or LONG_MIN
  701. * wcstoul -- ULONG_MAX
  702. * wcstol/wcstoul -- errno == ERANGE
  703. *
  704. * No digits or bad base return:
  705. * 0
  706. * endptr = nptr*
  707. *
  708. *Exceptions:
  709. * None.
  710. *
  711. *******************************************************************************/
  712. /* flag values */
  713. #define FL_UNSIGNED 1 /* wcstoul called */
  714. #define FL_NEG 2 /* negative sign found */
  715. #define FL_OVERFLOW 4 /* overflow occured */
  716. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  717. static unsigned long __cdecl wcstoxl (
  718. const wchar_t *nptr,
  719. const wchar_t **endptr,
  720. int ibase,
  721. int flags
  722. )
  723. {
  724. const wchar_t *p;
  725. wchar_t c;
  726. unsigned long number;
  727. unsigned digval;
  728. unsigned long maxval;
  729. p = nptr; /* p is our scanning pointer */
  730. number = 0; /* start with zero */
  731. c = *p++; /* read char */
  732. while ( iswspace(c) )
  733. c = *p++; /* skip whitespace */
  734. if (c == '-') {
  735. flags |= FL_NEG; /* remember minus sign */
  736. c = *p++;
  737. }
  738. else if (c == '+')
  739. c = *p++; /* skip sign */
  740. if (ibase < 0 || ibase == 1 || ibase > 36) {
  741. /* bad base! */
  742. if (endptr)
  743. /* store beginning of string in endptr */
  744. *endptr = nptr;
  745. return 0L; /* return 0 */
  746. }
  747. else if (ibase == 0) {
  748. /* determine base free-lance, based on first two chars of
  749. string */
  750. if (c != L'0')
  751. ibase = 10;
  752. else if (*p == L'x' || *p == L'X')
  753. ibase = 16;
  754. else
  755. ibase = 8;
  756. }
  757. if (ibase == 16) {
  758. /* we might have 0x in front of number; remove if there */
  759. if (c == L'0' && (*p == L'x' || *p == L'X')) {
  760. ++p;
  761. c = *p++; /* advance past prefix */
  762. }
  763. }
  764. /* if our number exceeds this, we will overflow on multiply */
  765. maxval = ULONG_MAX / ibase;
  766. for (;;) { /* exit in middle of loop */
  767. /* make sure c is not too big */
  768. if ( (unsigned)c > UCHAR_MAX )
  769. break;
  770. /* convert c to value */
  771. if ( iswdigit(c) )
  772. digval = c - L'0';
  773. else if ( iswalpha(c))
  774. digval = towupper(c) - L'A' + 10;
  775. else
  776. break;
  777. if (digval >= (unsigned)ibase)
  778. break; /* exit loop if bad digit found */
  779. /* record the fact we have read one digit */
  780. flags |= FL_READDIGIT;
  781. /* we now need to compute number = number * base + digval,
  782. but we need to know if overflow occured. This requires
  783. a tricky pre-check. */
  784. if (number < maxval || (number == maxval &&
  785. (unsigned long)digval <= ULONG_MAX % ibase)) {
  786. /* we won't overflow, go ahead and multiply */
  787. number = number * ibase + digval;
  788. }
  789. else {
  790. /* we would have overflowed -- set the overflow flag */
  791. flags |= FL_OVERFLOW;
  792. }
  793. c = *p++; /* read next digit */
  794. }
  795. --p; /* point to place that stopped scan */
  796. if (!(flags & FL_READDIGIT)) {
  797. /* no number there; return 0 and point to beginning of
  798. string */
  799. if (endptr)
  800. /* store beginning of string in endptr later on */
  801. p = nptr;
  802. number = 0L; /* return 0 */
  803. }
  804. else if ( (flags & FL_OVERFLOW) ||
  805. ( !(flags & FL_UNSIGNED) &&
  806. ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
  807. ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
  808. {
  809. /* overflow or signed overflow occurred */
  810. errno = ERANGE;
  811. if ( flags & FL_UNSIGNED )
  812. number = ULONG_MAX;
  813. else
  814. number = LONG_MAX;
  815. flags &= ~FL_NEG;
  816. }
  817. else if ((flags & FL_UNSIGNED) && (flags & FL_NEG)) {
  818. // Disallow a negative sign if we're reading an unsigned
  819. number = 0L;
  820. p = nptr;
  821. }
  822. if (endptr != NULL)
  823. /* store pointer to char that stopped the scan */
  824. *endptr = p;
  825. if (flags & FL_NEG)
  826. /* negate result if there was a neg sign */
  827. number = (unsigned long)(-(long)number);
  828. return number; /* done. */
  829. }
  830. long __cdecl My_wcstol (
  831. const wchar_t *nptr,
  832. wchar_t **endptr,
  833. int ibase
  834. )
  835. {
  836. return (long) wcstoxl(nptr, endptr, ibase, 0);
  837. }
  838. unsigned long __cdecl My_wcstoul (
  839. const wchar_t *nptr,
  840. wchar_t **endptr,
  841. int ibase
  842. )
  843. {
  844. return wcstoxl(nptr, endptr, ibase, FL_UNSIGNED);
  845. }
  846. #else
  847. #define My_wcstoui64 _wcstoui64
  848. #define My_wcstoul _wcstoul
  849. #endif
  850. LPWSTR
  851. FileTime2String(
  852. IN PLARGE_INTEGER Time,
  853. IN LPWSTR Buffer,
  854. IN ULONG BufferSize //in bytes
  855. )
  856. /*++
  857. Routine Description:
  858. This routine will take a file time and convert it into a string in
  859. the given buffer.
  860. Arguments:
  861. Return Value:
  862. The passed in string buffer.
  863. --*/
  864. {
  865. TIME_FIELDS timeFields;
  866. SYSTEMTIME systemTime;
  867. WCHAR dateString[32];
  868. WCHAR timeString[32];
  869. if (Time->QuadPart == 0) {
  870. //
  871. // If zero, return this string
  872. //
  873. (void)StringCbCopy( Buffer, BufferSize, L"<Undefined>" );
  874. } else {
  875. //
  876. // Convert time to desired format
  877. //
  878. FileTimeToSystemTime( (PFILETIME) Time, &systemTime );
  879. //
  880. // Get the date
  881. //
  882. GetDateFormat( LOCALE_USER_DEFAULT,
  883. DATE_SHORTDATE,
  884. &systemTime,
  885. NULL,
  886. dateString,
  887. sizeof( dateString ) / sizeof( dateString[0] ));
  888. //
  889. // Get the time
  890. //
  891. GetTimeFormat( LOCALE_USER_DEFAULT,
  892. TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,
  893. &systemTime,
  894. NULL,
  895. timeString,
  896. sizeof( timeString ) / sizeof( timeString[0] ));
  897. //
  898. // Return the generated strings
  899. //
  900. (void)StringCbCopy( Buffer, BufferSize, dateString );
  901. (void)StringCbCat( Buffer, BufferSize, L" " );
  902. (void)StringCbCat( Buffer, BufferSize, timeString );
  903. }
  904. return Buffer;
  905. }
  906. LPWSTR
  907. Guid2Str(
  908. IN GUID *Guid,
  909. IN LPWSTR Buffer,
  910. IN ULONG BufferSize //in bytes
  911. )
  912. /*++
  913. Routine Description:
  914. This routine will convert the given guid into a string and return
  915. that string in the given buffer.
  916. Arguments:
  917. Return Value:
  918. The passed in string buffer.
  919. --*/
  920. {
  921. LPWSTR guidString;
  922. if (StringFromIID( Guid, &guidString ) != S_OK) {
  923. (void)StringCbCopy( Buffer, BufferSize, L"<Invalid GUID>" );
  924. } else {
  925. //
  926. // I want to exclude the starting and ending brace
  927. //
  928. (void)StringCbCopyN( Buffer, BufferSize, guidString+1, (36 * sizeof(WCHAR)) );
  929. CoTaskMemFree( guidString );
  930. }
  931. return Buffer;
  932. }