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.

731 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: myutil.cxx
  7. //
  8. // Contents: Helper APIs for Sharing Tool
  9. //
  10. // History: 6-Jun-93 WilliamW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.hxx"
  14. #pragma hdrstop
  15. ////////////////////////////////////////////////////////////////////////////
  16. //+-------------------------------------------------------------------------
  17. //
  18. // Member: MyGetLastComponent, public
  19. //
  20. // Synopsis: Parse a string to a (prefix, last-component) pair. Any
  21. // trailing text after L'.' will be ignored
  22. //
  23. // History: 07-May-93 WilliamW Created
  24. //
  25. // Notes: pszPrefix and pszLastComponent should be pre-allocated
  26. //
  27. //--------------------------------------------------------------------------
  28. VOID
  29. MyGetLastComponent(
  30. IN PWSTR pszStr,
  31. OUT PWSTR pszPrefix,
  32. OUT PWSTR pszLastComponent
  33. )
  34. {
  35. PWSTR pszTmp = NULL;
  36. PWSTR pszTmpLast = NULL;
  37. //
  38. // Manufacture the prefix part by replacing L'\\' with L'\0'
  39. //
  40. wcscpy(pszPrefix, pszStr);
  41. pszTmp = wcsrchr(pszPrefix, L'\\');
  42. if (pszTmp != NULL)
  43. {
  44. *pszTmp = L'\0';
  45. //
  46. // Extract the last component. The L'.' part will be replaced
  47. // by a L'\0'
  48. //
  49. pszTmpLast = pszTmp + 1;
  50. pszTmp = wcsrchr(pszTmpLast, L'.');
  51. if (pszTmp != NULL)
  52. {
  53. //
  54. // Replace with a L'\0' character
  55. //
  56. *pszTmp = L'\0';
  57. }
  58. wcscpy(pszLastComponent, pszTmpLast);
  59. }
  60. else
  61. {
  62. *pszPrefix = L'\0';
  63. wcscpy(pszLastComponent, pszStr);
  64. }
  65. }
  66. //+-------------------------------------------------------------------------
  67. //
  68. // Member: MyFindLastComponent, public
  69. //
  70. // Synopsis: Parse a string to find the last component. This is different
  71. // from MyGetLastComponent as it doesn't copy any data, but just
  72. // looks for the last backslash and points one after it.
  73. //
  74. // History: 21-Nov-94 BruceFo
  75. //
  76. //--------------------------------------------------------------------------
  77. PWSTR
  78. MyFindLastComponent(
  79. IN const WCHAR* pszStr
  80. )
  81. {
  82. PWSTR pszTmp = wcsrchr(pszStr, L'\\');
  83. if (pszTmp != NULL)
  84. {
  85. return pszTmp + 1;
  86. }
  87. else
  88. {
  89. return (PWSTR)pszStr; // cast away const
  90. }
  91. }
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Member: MyGetNextComponent(), public
  95. //
  96. // Synopsis: Parse a string to a (next-components, remaing-components)
  97. // pair. Any
  98. //
  99. // History: 07-May-93 WilliamW Created
  100. //
  101. // Notes: pszNextComponent and pszRemaining should be pre-allocated.
  102. //
  103. //--------------------------------------------------------------------------
  104. VOID
  105. MyGetNextComponent(
  106. IN PWSTR pszStr,
  107. OUT PWSTR pszNextComponent,
  108. OUT PWSTR pszRemaining
  109. )
  110. {
  111. PWSTR pszTmp = NULL;
  112. if (*pszStr == L'\0')
  113. {
  114. *pszNextComponent = *pszRemaining = L'\0';
  115. return;
  116. }
  117. #if DBG == 1
  118. if (*pszStr == L'\\')
  119. {
  120. appDebugOut((DEB_IERROR,
  121. "WARNING: MyGetNextComponent takes a relative path as its first argument\n"));
  122. }
  123. #endif // DBG == 1
  124. //
  125. // Manufacture the next component part by replacing L'\\' with L'\0'
  126. //
  127. pszTmp = wcschr(pszStr, L'\\');
  128. if (pszTmp != NULL)
  129. {
  130. ULONG cchNextComponent = (ULONG)(pszTmp - pszStr);
  131. wcsncpy(pszNextComponent, pszStr, cchNextComponent);
  132. pszNextComponent[cchNextComponent] = L'\0';
  133. //
  134. // Handle the remaining component.
  135. //
  136. wcscpy(pszRemaining, pszTmp + 1);
  137. }
  138. else
  139. {
  140. //
  141. // No remaining part, this is the last component
  142. //
  143. *pszRemaining = L'\0';
  144. wcscpy(pszNextComponent, pszStr);
  145. }
  146. }
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Method: MyStrStr
  150. //
  151. // Synopsis: A case insensitive version of wcsstr (i.e. strstr)
  152. //
  153. //--------------------------------------------------------------------------
  154. PWSTR
  155. MyStrStr(
  156. IN PWSTR pszInStr,
  157. IN PWSTR pszInSubStr
  158. )
  159. {
  160. if ( pszInStr == NULL
  161. || pszInSubStr == NULL
  162. || *pszInStr == L'\0'
  163. || *pszInSubStr == L'\0')
  164. {
  165. return NULL;
  166. }
  167. INT iSubStrLen = wcslen(pszInSubStr);
  168. INT iStrLen = wcslen(pszInStr);
  169. PWSTR pszHeadInStr = pszInStr;
  170. PWSTR pszTailInStr = pszInStr + iSubStrLen;
  171. PWSTR pszEndInStr = pszInStr + iStrLen;
  172. while (pszTailInStr <= pszEndInStr)
  173. {
  174. if (0 != _wcsnicmp(pszHeadInStr, pszInSubStr, iSubStrLen))
  175. {
  176. return pszHeadInStr;
  177. }
  178. pszHeadInStr++;
  179. pszTailInStr++;
  180. }
  181. return NULL;
  182. }
  183. //+-------------------------------------------------------------------------
  184. //
  185. // Method: MyFindPostfix
  186. //
  187. // Synopsis: Match the prefix with the string. If the string doesn't have
  188. // the prefix, return a pointer to the string itself. If it does,
  189. // then check to see if the character after the prefix is a
  190. // backslash. If it is, return a pointer to the character
  191. // following the backslash. Otherwise, return a pointer to the
  192. // character immediately after the prefix.
  193. //
  194. // Examples:
  195. // string prefix return
  196. // \foo\bar\baz \bad \foo\bar\baz
  197. // \foo\bar\baz \foo\bar baz
  198. // \foo\bar\baz \f oo\bar\baz
  199. //
  200. //--------------------------------------------------------------------------
  201. PWSTR
  202. MyFindPostfix(
  203. IN PWSTR pszString,
  204. IN PWSTR pszPrefix
  205. )
  206. {
  207. UINT cchPrefixLen = wcslen(pszPrefix);
  208. if (0 == _wcsnicmp(pszString, pszPrefix, cchPrefixLen))
  209. {
  210. PWSTR pszReturn = pszString + cchPrefixLen;
  211. if (*pszReturn == L'\\')
  212. {
  213. //
  214. // skip past the leading backslash.
  215. //
  216. ++pszReturn;
  217. }
  218. return pszReturn;
  219. }
  220. else
  221. {
  222. // prefix didn't match, return argument string
  223. // appDebugOut((DEB_ITRACE,
  224. // "No postfix of ('%ws', '%ws')\n",
  225. // pszString,
  226. // pszPrefix));
  227. return pszString;
  228. }
  229. }
  230. //+-------------------------------------------------------------------------
  231. //
  232. // Function: MyFormatMessageText
  233. //
  234. // Synopsis: Given a resource IDs, load strings from given instance
  235. // and format the string into a buffer
  236. //
  237. // History: 11-Aug-93 WilliamW Created.
  238. //
  239. //--------------------------------------------------------------------------
  240. VOID
  241. MyFormatMessageText(
  242. IN HRESULT dwMsgId,
  243. IN PWSTR pszBuffer,
  244. IN DWORD dwBufferSize,
  245. IN va_list * parglist
  246. )
  247. {
  248. //
  249. // get message from system or app msg file.
  250. //
  251. DWORD dwReturn = FormatMessage(
  252. (dwMsgId >= MSG_FIRST_MESSAGE)
  253. ? FORMAT_MESSAGE_FROM_HMODULE
  254. : FORMAT_MESSAGE_FROM_SYSTEM,
  255. NULL,
  256. dwMsgId,
  257. LANG_USER_DEFAULT,
  258. pszBuffer,
  259. dwBufferSize,
  260. parglist);
  261. if (0 == dwReturn) // couldn't find message
  262. {
  263. appDebugOut((DEB_IERROR,
  264. "Formatmessage failed = 0x%08lx\n",
  265. GetLastError()));
  266. WCHAR szText[200];
  267. LoadString(g_hInstance,
  268. (dwMsgId >= MSG_FIRST_MESSAGE)
  269. ? IDS_APP_MSG_NOT_FOUND
  270. : IDS_SYS_MSG_NOT_FOUND,
  271. szText,
  272. ARRAYLEN(szText));
  273. wsprintf(pszBuffer,szText,dwMsgId);
  274. }
  275. }
  276. //+-------------------------------------------------------------------------
  277. //
  278. // Function: MyFormatMessage
  279. //
  280. // Synopsis: Given a resource IDs, load strings from given instance
  281. // and format the string into a buffer
  282. //
  283. // History: 11-Aug-93 WilliamW Created.
  284. //
  285. //--------------------------------------------------------------------------
  286. VOID
  287. MyFormatMessage(
  288. IN HRESULT dwMsgId,
  289. IN PWSTR pszBuffer,
  290. IN DWORD dwBufferSize,
  291. ...
  292. )
  293. {
  294. va_list arglist;
  295. va_start(arglist, dwBufferSize);
  296. MyFormatMessageText(dwMsgId, pszBuffer, dwBufferSize, &arglist);
  297. va_end(arglist);
  298. }
  299. //+---------------------------------------------------------------------------
  300. //
  301. // Function: NewDup
  302. //
  303. // Synopsis: Duplicate a string using '::new'
  304. //
  305. // Arguments:
  306. //
  307. // Returns:
  308. //
  309. // History: 28-Dec-94 BruceFo Created
  310. //
  311. //----------------------------------------------------------------------------
  312. PWSTR
  313. NewDup(
  314. IN const WCHAR* psz
  315. )
  316. {
  317. if (NULL == psz)
  318. {
  319. return NULL;
  320. }
  321. PWSTR pszRet = new WCHAR[wcslen(psz) + 1];
  322. if (NULL == pszRet)
  323. {
  324. appDebugOut((DEB_ERROR,"OUT OF MEMORY\n"));
  325. return NULL;
  326. }
  327. wcscpy(pszRet, psz);
  328. return pszRet;
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. // Function: wcsistr
  333. //
  334. // Synopsis: Same as wcsstr (find string in string), but case-insensitive
  335. //
  336. // Arguments:
  337. //
  338. // Returns:
  339. //
  340. // History: 2-Feb-95 BruceFo Created
  341. //
  342. //----------------------------------------------------------------------------
  343. wchar_t*
  344. wcsistr(
  345. const wchar_t* string1,
  346. const wchar_t* string2
  347. )
  348. {
  349. if ((NULL == string2) || (NULL == string1))
  350. {
  351. // do whatever wcsstr would do
  352. return wcsstr(string1, string2);
  353. }
  354. wchar_t* s1dup = NewDup(string1);
  355. wchar_t* s2dup = NewDup(string2);
  356. wchar_t* ret = NULL;
  357. if (NULL != s1dup && NULL != s2dup)
  358. {
  359. _wcslwr(s1dup); // lower case everything to make case-insensitive
  360. _wcslwr(s2dup);
  361. ret = wcsstr(s1dup, s2dup);
  362. }
  363. delete[] s1dup;
  364. delete[] s2dup;
  365. return ret;
  366. }
  367. //+---------------------------------------------------------------------------
  368. //
  369. // Function: GetResourceString
  370. //
  371. // Synopsis: Load a resource string, are return a "new"ed copy
  372. //
  373. // Arguments: [dwId] -- a resource string ID
  374. //
  375. // Returns: new memory copy of a string
  376. //
  377. // History: 5-Apr-95 BruceFo Created
  378. //
  379. //----------------------------------------------------------------------------
  380. PWSTR
  381. GetResourceString(
  382. IN DWORD dwId
  383. )
  384. {
  385. WCHAR sz[50];
  386. if (0 == LoadString(g_hInstance, dwId, sz, ARRAYLEN(sz)))
  387. {
  388. return NULL;
  389. }
  390. else
  391. {
  392. return NewDup(sz);
  393. }
  394. }
  395. //+-------------------------------------------------------------------------
  396. //
  397. // Function: IsDfsRoot
  398. //
  399. // Synopsis: Determine if the path passed in is a Dfs root, in form only.
  400. // Namely, does it look like "\\machine-or-domain\share"?
  401. //
  402. // Arguments: none
  403. //
  404. // Returns: nothing
  405. //
  406. // History: 18-Apr-96 BruceFo Created
  407. //
  408. //--------------------------------------------------------------------------
  409. BOOL
  410. IsDfsRoot(
  411. IN LPWSTR pszRoot
  412. )
  413. {
  414. if (NULL != pszRoot
  415. && pszRoot[0] == L'\\'
  416. && pszRoot[1] == L'\\'
  417. && pszRoot[2] != L'\\' // might be null
  418. )
  419. {
  420. LPWSTR pszTmp = wcschr(pszRoot + 2, L'\\');
  421. if (pszTmp != NULL)
  422. {
  423. if (pszTmp[1] != L'\0'
  424. && pszTmp[1] != L'\\'
  425. )
  426. {
  427. // ok, we've got "\\xxx\y...."
  428. // Now make sure it doesn't have a fourth backslash
  429. pszTmp = wcschr(pszTmp + 2, L'\\');
  430. if (pszTmp == NULL)
  431. {
  432. return TRUE;
  433. }
  434. }
  435. }
  436. }
  437. return FALSE;
  438. }
  439. //+-------------------------------------------------------------------------
  440. //
  441. // Function: IsDfsShare
  442. //
  443. // Synopsis: Determine if the given share on the given server is a Dfs
  444. // share. This actually contacts the machine.
  445. //
  446. // Arguments: none
  447. //
  448. // Returns: nothing
  449. //
  450. // History: 18-Apr-96 BruceFo Created
  451. //
  452. //--------------------------------------------------------------------------
  453. DWORD
  454. IsDfsShare(
  455. IN LPWSTR pszServer,
  456. IN LPWSTR pszShare,
  457. OUT BOOL* pfIsDfs
  458. )
  459. {
  460. PSHARE_INFO_1005 pshi1005;
  461. NET_API_STATUS ret = NetShareGetInfo(pszServer, pszShare, 1005, (LPBYTE*)&pshi1005);
  462. if (NERR_Success == ret)
  463. {
  464. if (pshi1005->shi1005_flags & SHI1005_FLAGS_DFS)
  465. {
  466. *pfIsDfs = TRUE;
  467. }
  468. else
  469. {
  470. appDebugOut((DEB_ITRACE,
  471. "%ws not a Dfs share\n",
  472. pszShare));
  473. }
  474. NetApiBufferFree(pshi1005);
  475. }
  476. else
  477. {
  478. // This could be an access denied.
  479. appDebugOut((DEB_ERROR,
  480. "NetShareGetInfo(NULL, %ws...) failed, 0x%08lx\n",
  481. pszShare,
  482. ret));
  483. }
  484. return ret;
  485. }
  486. //+-------------------------------------------------------------------------
  487. //
  488. // Member: FindDfsRoot, public
  489. //
  490. // Synopsis: Parse a string to find the Dfs root. Returns a pointer to
  491. //
  492. // History: 22-Apr-96 BruceFo
  493. //
  494. //--------------------------------------------------------------------------
  495. BOOL
  496. FindDfsRoot(
  497. IN PWSTR pszDfsPath,
  498. OUT PWSTR pszDfsRoot
  499. )
  500. {
  501. PWSTR pszTmp;
  502. if (NULL != pszDfsPath
  503. && pszDfsPath[0] == L'\\'
  504. && pszDfsPath[1] == L'\\'
  505. && pszDfsPath[2] != L'\\'
  506. && pszDfsPath[2] != L'\0'
  507. && (NULL != (pszTmp = wcschr(pszDfsPath + 3, L'\\')))
  508. && pszTmp[1] != L'\\'
  509. && pszTmp[1] != L'\0'
  510. )
  511. {
  512. pszTmp = wcschr(pszTmp + 2, L'\\');
  513. if (NULL != pszTmp)
  514. {
  515. // the thing passed in was of the form "\\xxx\yyy\..."
  516. int len = (int)(pszTmp - pszDfsPath);
  517. wcsncpy(pszDfsRoot, pszDfsPath, len);
  518. pszDfsRoot[len] = L'\0';
  519. }
  520. else
  521. {
  522. // the thing passed in was of the form "\\xxx\yyy"
  523. wcscpy(pszDfsRoot, pszDfsPath);
  524. }
  525. appDebugOut((DEB_IERROR,
  526. "Dfs root of %ws is %ws\n",
  527. pszDfsPath, pszDfsRoot));
  528. return TRUE;
  529. }
  530. else
  531. {
  532. return FALSE;
  533. }
  534. }
  535. #define MAX_MESSAGE_BUF 8192
  536. #define MAX_ANSI_MESSAGE_BUF (MAX_MESSAGE_BUF * 3)
  537. WCHAR szMsgBuf[MAX_MESSAGE_BUF];
  538. CHAR szAnsiBuf[MAX_ANSI_MESSAGE_BUF];
  539. VOID
  540. StatusMessage(
  541. IN HRESULT hr,
  542. ...
  543. )
  544. {
  545. va_list arglist;
  546. va_start(arglist, hr);
  547. ULONG written;
  548. MyFormatMessageText(hr, szMsgBuf, ARRAYLEN(szMsgBuf), &arglist);
  549. written = WideCharToMultiByte(CP_OEMCP, 0,
  550. szMsgBuf, wcslen(szMsgBuf),
  551. szAnsiBuf, MAX_ANSI_MESSAGE_BUF,
  552. NULL, NULL);
  553. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), szAnsiBuf, written, &written, NULL);
  554. va_end(arglist);
  555. }
  556. VOID
  557. ErrorMessage(
  558. IN HRESULT hr,
  559. ...
  560. )
  561. {
  562. va_list arglist;
  563. va_start(arglist, hr);
  564. ULONG written;
  565. MyFormatMessageText(hr, szMsgBuf, ARRAYLEN(szMsgBuf), &arglist);
  566. written = WideCharToMultiByte(CP_OEMCP, 0,
  567. szMsgBuf, wcslen(szMsgBuf),
  568. szAnsiBuf, MAX_ANSI_MESSAGE_BUF,
  569. NULL, NULL);
  570. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), szAnsiBuf, written, &written, NULL);
  571. va_end(arglist);
  572. exit(1);
  573. }
  574. VOID
  575. DfsErrorMessage(
  576. IN NET_API_STATUS status
  577. )
  578. {
  579. ULONG written;
  580. MyFormatMessage(MSG_ERROR, szMsgBuf, ARRAYLEN(szMsgBuf), status);
  581. written = WideCharToMultiByte(CP_OEMCP, 0,
  582. szMsgBuf, wcslen(szMsgBuf),
  583. szAnsiBuf, MAX_ANSI_MESSAGE_BUF,
  584. NULL, NULL);
  585. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), szAnsiBuf, written, &written, NULL);
  586. PWSTR pszDll = L"netmsg.dll";
  587. HINSTANCE hinst = LoadLibrary(pszDll);
  588. if (NULL == hinst)
  589. {
  590. MyFormatMessage(MSG_NO_MESSAGES, szMsgBuf, ARRAYLEN(szMsgBuf), pszDll);
  591. }
  592. else
  593. {
  594. DWORD dwReturn = FormatMessage(
  595. FORMAT_MESSAGE_FROM_HMODULE
  596. | FORMAT_MESSAGE_IGNORE_INSERTS,
  597. hinst,
  598. status,
  599. LANG_USER_DEFAULT,
  600. szMsgBuf,
  601. ARRAYLEN(szMsgBuf),
  602. NULL);
  603. FreeLibrary(hinst);
  604. if (0 == dwReturn) // couldn't find message
  605. {
  606. // try system messages
  607. dwReturn = FormatMessage(
  608. FORMAT_MESSAGE_FROM_SYSTEM
  609. | FORMAT_MESSAGE_IGNORE_INSERTS,
  610. NULL,
  611. status,
  612. LANG_USER_DEFAULT,
  613. szMsgBuf,
  614. ARRAYLEN(szMsgBuf),
  615. NULL);
  616. if (0 == dwReturn) // couldn't find message
  617. {
  618. MyFormatMessage(MSG_ERROR_UNKNOWN, szMsgBuf, ARRAYLEN(szMsgBuf));
  619. }
  620. }
  621. }
  622. written = WideCharToMultiByte(CP_OEMCP, 0,
  623. szMsgBuf, wcslen(szMsgBuf),
  624. szAnsiBuf, MAX_ANSI_MESSAGE_BUF,
  625. NULL, NULL);
  626. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), szAnsiBuf, written, &written, NULL);
  627. exit(1);
  628. }
  629. VOID
  630. Usage(
  631. VOID
  632. )
  633. {
  634. ErrorMessage(MSG_USAGE);
  635. }