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.

587 lines
15 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: util.cxx
  7. //
  8. // Contents: DRT support routines
  9. //
  10. // History: 22-Sep-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include "headers.cxx"
  14. #pragma hdrstop
  15. #include <stdarg.h>
  16. #include <direct.h>
  17. #include <io.h>
  18. #if DBG == 1
  19. #include <dfdeb.hxx>
  20. #endif
  21. #define DEFAULT_DATA_DIR "."
  22. BOOL fExitOnFail = TRUE;
  23. char szOrigDir[_MAX_PATH] = ".";
  24. // Preserve the current directory and change
  25. // directory into the data directory
  26. void SetData(void)
  27. {
  28. char *pszDataDir;
  29. _getcwd(szOrigDir, _MAX_PATH);
  30. pszDataDir = getenv("DRTDATA");
  31. if (pszDataDir == NULL)
  32. pszDataDir = DEFAULT_DATA_DIR;
  33. _chdir(pszDataDir);
  34. }
  35. // Clean up the data directory
  36. void CleanData(void)
  37. {
  38. _unlink(OlecsOut(DRTDF));
  39. _unlink(OlecsOut(MARSHALDF));
  40. }
  41. // Restore the original directory
  42. void UnsetData(void)
  43. {
  44. _chdir(szOrigDir);
  45. }
  46. // Output a message if fVerbose is true
  47. void out(char *fmt, ...)
  48. {
  49. va_list args;
  50. if (fVerbose)
  51. {
  52. va_start(args, fmt);
  53. vprintf(fmt, args);
  54. va_end(args);
  55. }
  56. }
  57. // internal error print
  58. void _errorprint (char *fmt, va_list args)
  59. {
  60. #if !defined(FLAT) || defined(FPRINTF_WORKS)
  61. fprintf(stderr, "** Fatal error **: ");
  62. vfprintf(stderr, fmt, args);
  63. #else
  64. printf("** Fatal error **: ");
  65. vprintf(fmt, args);
  66. #endif
  67. }
  68. // error print
  69. void errorprint (char *fmt, ...)
  70. {
  71. va_list args;
  72. va_start (args, fmt);
  73. _errorprint (fmt, args);
  74. va_end (args);
  75. }
  76. // Print out an error message and terminate the DRT
  77. void error(int code, char *fmt, ...)
  78. {
  79. va_list args;
  80. va_start(args, fmt);
  81. _errorprint (fmt, args);
  82. va_end(args);
  83. CleanData();
  84. UnsetData();
  85. exit(code);
  86. }
  87. // Converts a TCHAR string to a char pointer in a temporary buffer
  88. // This implementation treats the conversion buffer as a circular
  89. // buffer so more than one string can be held (depending on the size
  90. // of the strings)
  91. #define BUFSIZE 1024
  92. char *OlecsOut(OLECHAR const *ptcs)
  93. {
  94. #ifdef OLEWIDECHAR
  95. static char szBuffer[BUFSIZE];
  96. static char *pszBuf = szBuffer;
  97. char *pszTmp;
  98. if (ptcs == NULL)
  99. return NULL;
  100. if (wcslen(ptcs) >= (size_t)(BUFSIZE-(pszBuf-szBuffer)))
  101. pszBuf = szBuffer;
  102. wcstombs(pszBuf, ptcs, BUFSIZE);
  103. szBuffer[BUFSIZE-1] = 0;
  104. pszTmp = pszBuf;
  105. pszBuf += strlen(pszBuf)+1;
  106. return pszTmp;
  107. #else
  108. return (char *)ptcs;
  109. #endif
  110. }
  111. typedef struct
  112. {
  113. SCODE sc;
  114. char *text;
  115. } StatusCodeText;
  116. static StatusCodeText scodes[] =
  117. {
  118. S_OK, "S_OK",
  119. S_FALSE, "S_FALSE",
  120. STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
  121. STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
  122. STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND",
  123. STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
  124. STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
  125. STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
  126. STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
  127. STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
  128. STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
  129. STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED",
  130. STG_E_SEEKERROR, "STG_E_SEEKERROR",
  131. STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
  132. STG_E_READFAULT, "STG_E_READFAULT",
  133. STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION",
  134. STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
  135. STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
  136. STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
  137. STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
  138. STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
  139. STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
  140. STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
  141. STG_E_UNKNOWN, "STG_E_UNKNOWN",
  142. STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
  143. STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
  144. STG_E_INUSE, "STG_E_INUSE",
  145. STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
  146. STG_E_REVERTED, "STG_E_REVERTED",
  147. STG_E_CANTSAVE, "STG_E_CANTSAVE",
  148. STG_E_OLDFORMAT, "STG_E_OLDFORMAT",
  149. STG_E_OLDDLL, "STG_E_OLDDLL",
  150. STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED",
  151. STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE",
  152. STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS",
  153. STG_S_CONVERTED, "STG_S_CONVERTED"
  154. };
  155. #define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
  156. // Convert a status code to text
  157. char *ScText(SCODE sc)
  158. {
  159. int i;
  160. for (i = 0; i<NSCODETEXT; i++)
  161. if (scodes[i].sc == sc)
  162. return scodes[i].text;
  163. return "?";
  164. }
  165. // Output a call result and check for failure
  166. HRESULT Result(HRESULT hr)
  167. {
  168. SCODE sc;
  169. sc = DfGetScode(hr);
  170. out(" - %s (0x%lX)\n", ScText(sc), sc);
  171. if (FAILED(sc) && fExitOnFail)
  172. error(EXIT_BADSC, "Unexpected call failure\n");
  173. return hr;
  174. }
  175. // Perform Result() when the expectation is failure
  176. HRESULT IllResult(char *pszText, HRESULT hr)
  177. {
  178. SCODE sc;
  179. sc = DfGetScode(hr);
  180. out("%s - %s (0x%lX)\n", pszText, ScText(sc), sc);
  181. if (SUCCEEDED(sc) && fExitOnFail)
  182. error(EXIT_BADSC, "Unexpected call success\n");
  183. return hr;
  184. }
  185. // DEBUG - Check for memory leaks
  186. void CheckMemory(void)
  187. {
  188. #if DBG == 1
  189. if (fVerbose || DfGetMemAlloced() != 0)
  190. {
  191. out("Memory held: %lu bytes\n", DfGetMemAlloced());
  192. if (DfGetMemAlloced() != 0)
  193. {
  194. DfPrintAllocs();
  195. error(EXIT_BADSC, "Memory leak\n");
  196. }
  197. }
  198. #endif
  199. }
  200. // DEBUG - Set the debugging level
  201. void SetDebug(ULONG ulDf, ULONG ulMsf)
  202. {
  203. #if DBG == 1
  204. DfDebug(ulDf, ulMsf);
  205. #endif
  206. }
  207. // Check whether a given storage has a certain
  208. // structure or not
  209. // Structure is given as a string with elements:
  210. // <Type><Name><Options>[,...]
  211. // Type - d for docfile and s for stream
  212. // Name - Characters up to a '(' or ','
  213. // Options - For a docfile, you can specify a recursive check
  214. // in parentheses
  215. //
  216. // Example: dDocfile(sStream,dDocfile)
  217. char *VerifyStructure(IStorage *pstg, char *pszStructure)
  218. {
  219. char szName[CWCSTORAGENAME], *psz;
  220. IStorage *pstgChild;
  221. char chType;
  222. SCODE sc;
  223. CStrList sl;
  224. SStrEntry *pse;
  225. IEnumSTATSTG *penm;
  226. STATSTG stat;
  227. OLECHAR atcName[CWCSTORAGENAME];
  228. if (FAILED(sc = DfGetScode(pstg->EnumElements(0, NULL, 0, &penm))))
  229. error(EXIT_BADSC, "VerifyStructure: Unable to create enumerator - "
  230. "%s (0x%lX)\n", ScText(sc), sc);
  231. for (;;)
  232. {
  233. sc = DfGetScode(penm->Next(1, &stat, NULL));
  234. if (sc == S_FALSE)
  235. break;
  236. else if (FAILED(sc))
  237. error(EXIT_BADSC, "VerifyStructure: Unable to enumerate - "
  238. "%s (0x%lX)\n", ScText(sc), sc);
  239. pse = sl.Add(stat.pwcsName);
  240. if (pse == NULL)
  241. error(EXIT_OOM, "VerifyStructure: Unable to allocate string\n");
  242. pse->user.dw = stat.type;
  243. drtMemFree(stat.pwcsName);
  244. }
  245. penm->Release();
  246. while (*pszStructure && *pszStructure != ')')
  247. {
  248. chType = *pszStructure++;
  249. psz = szName;
  250. while (*pszStructure && *pszStructure != '(' &&
  251. *pszStructure != ')' && *pszStructure != ',')
  252. *psz++ = *pszStructure++;
  253. *psz = 0;
  254. ATOOLE(szName, atcName, CWCSTORAGENAME);
  255. pse = sl.Find(atcName);
  256. if (pse == NULL)
  257. error(EXIT_BADSC, "VerifyStructure: '%s' not found\n", szName);
  258. switch(chType)
  259. {
  260. case 'd':
  261. if (pse->user.dw != STGTY_STORAGE)
  262. error(EXIT_BADSC, "VerifyStructure: '%s' is not a storage\n",
  263. szName);
  264. sc = DfGetScode(pstg->OpenStorage(atcName, NULL,
  265. STGP(STGM_READWRITE), NULL,
  266. 0, &pstgChild));
  267. if (FAILED(sc))
  268. error(EXIT_BADSC, "VerifyStructure: can't open storage "
  269. "'%s' - %s\n", szName, ScText(sc));
  270. if (*pszStructure == '(')
  271. pszStructure = VerifyStructure(pstgChild, pszStructure+1)+1;
  272. pstgChild->Release();
  273. break;
  274. case 's':
  275. if (pse->user.dw != STGTY_STREAM)
  276. error(EXIT_BADSC, "VerifyStructure: '%s' is not a stream\n",
  277. szName);
  278. break;
  279. }
  280. sl.Remove(pse);
  281. if (*pszStructure == ',')
  282. pszStructure++;
  283. }
  284. for (pse = sl.GetHead(); pse; pse = pse->pseNext)
  285. error(EXIT_BADSC, "VerifyStructure: additional member '%s'\n",
  286. OlecsOut(pse->atc));
  287. return pszStructure;
  288. }
  289. // Creates a structure using the same syntax
  290. // as VerifyStructure
  291. char *CreateStructure(IStorage *pstg, char *pszStructure)
  292. {
  293. char szName[CWCSTORAGENAME], *psz;
  294. IStorage *pstgChild;
  295. IStream *pstmChild;
  296. char chType;
  297. SCODE sc;
  298. OLECHAR atcName[CWCSTORAGENAME];
  299. while (*pszStructure && *pszStructure != ')')
  300. {
  301. chType = *pszStructure++;
  302. psz = szName;
  303. while (*pszStructure && *pszStructure != '(' &&
  304. *pszStructure != ')' && *pszStructure != ',')
  305. *psz++ = *pszStructure++;
  306. *psz = 0;
  307. ATOOLE(szName, atcName, CWCSTORAGENAME);
  308. switch(chType)
  309. {
  310. case 'd':
  311. sc = DfGetScode(pstg->CreateStorage(atcName, STGP(STGM_READWRITE),
  312. 0, 0, &pstgChild));
  313. if (FAILED(sc))
  314. error(EXIT_BADSC, "CreateStructure: can't create storage "
  315. "'%s' - %s\n", szName, ScText(sc));
  316. if (*pszStructure == '(')
  317. pszStructure = CreateStructure(pstgChild, pszStructure+1)+1;
  318. pstgChild->Release();
  319. break;
  320. case 's':
  321. sc = DfGetScode(pstg->CreateStream(atcName, STMP(STGM_READWRITE),
  322. 0, 0, &pstmChild));
  323. if (FAILED(sc))
  324. error(EXIT_BADSC, "CreateStructure: can't create stream "
  325. "'%s' - %s\n", szName, ScText(sc));
  326. pstmChild->Release();
  327. break;
  328. }
  329. if (*pszStructure == ',')
  330. pszStructure++;
  331. }
  332. pstg->Commit(0);
  333. return pszStructure;
  334. }
  335. // Verifies the fields of a STATSTG
  336. void VerifyStat(STATSTG *pstat, OLECHAR *ptcsName, DWORD type, DWORD grfMode)
  337. {
  338. if (ptcsName == NULL)
  339. {
  340. if (pstat->pwcsName != NULL)
  341. error(EXIT_BADSC, "Stat name should be NULL - is %p\n",
  342. pstat->pwcsName);
  343. }
  344. else if (olecscmp(pstat->pwcsName, ptcsName))
  345. error(EXIT_BADSC, "Stat name mismatch - has '%s' vs. '%s'\n",
  346. OlecsOut(pstat->pwcsName), OlecsOut(ptcsName));
  347. if (pstat->type != type)
  348. error(EXIT_BADSC, "Stat type mismatch - has %lu vs. %lu\n",
  349. pstat->type, type);
  350. if (pstat->grfMode != grfMode)
  351. error(EXIT_BADSC, "Stat mode mismatch - has 0x%lX vs. 0x%lX\n",
  352. pstat->grfMode, grfMode);
  353. }
  354. // Checks on a file's existence
  355. BOOL Exists(OLECHAR *file)
  356. {
  357. OFSTRUCT of;
  358. #ifndef OLEWIDECHAR
  359. return OpenFile(file, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
  360. HFILE_ERROR ? TRUE : FALSE;
  361. #else
  362. char szName[_MAX_PATH];
  363. wcstombs(szName, file, _MAX_PATH);
  364. return OpenFile(szName, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
  365. HFILE_ERROR ? TRUE : FALSE;
  366. #endif
  367. }
  368. // Gets a file's length
  369. ULONG Length(OLECHAR *file)
  370. {
  371. ULONG cb;
  372. #ifndef WIN32
  373. OFSTRUCT of;
  374. int hf;
  375. hf = OpenFile(file, &of, OF_READ | OF_SHARE_DENY_NONE);
  376. if (hf == HFILE_ERROR)
  377. error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file));
  378. cb = (ULONG)_llseek(hf, 0, SEEK_END);
  379. if (cb == (ULONG)HFILE_ERROR)
  380. error(EXIT_BADSC, "Length: Unable to get length for '%s'\n",
  381. OlecsOut(file));
  382. _lclose(hf);
  383. #else
  384. // use WIN32 APIs
  385. HANDLE hf;
  386. #if !defined(UNICODE)
  387. // Chicago - call ANSI CreateFile
  388. char szName[_MAX_PATH];
  389. if (wcstombs(szName, file, _MAX_PATH) == (size_t)-1)
  390. return 0;
  391. hf = CreateFile (
  392. szName,
  393. GENERIC_READ,
  394. FILE_SHARE_READ | FILE_SHARE_WRITE,
  395. NULL,
  396. OPEN_EXISTING,
  397. FILE_ATTRIBUTE_NORMAL,
  398. NULL
  399. );
  400. #else
  401. hf = CreateFile (
  402. file,
  403. GENERIC_READ,
  404. FILE_SHARE_READ | FILE_SHARE_WRITE,
  405. NULL,
  406. OPEN_EXISTING,
  407. FILE_ATTRIBUTE_NORMAL,
  408. NULL
  409. );
  410. #endif // !defined(UNICODE)
  411. if (hf == INVALID_HANDLE_VALUE)
  412. error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file));
  413. cb = (ULONG)GetFileSize(hf, NULL);
  414. if (cb == (ULONG)0xFFFFFFFF)
  415. error(EXIT_BADSC, "Length: Unable to get length for '%s'\n",
  416. OlecsOut(file));
  417. CloseHandle(hf);
  418. #endif // !WIN32
  419. return cb;
  420. }
  421. // Original mode when a new mode is forced
  422. // Used by ForceDirect, ForceTransacted and Unforce
  423. static DWORD dwTransOld;
  424. static DWORD dwRDWOld;
  425. // Forces direct mode to be active
  426. // Note: this uses a static variable so it can\'t be nested
  427. void ForceDirect(void)
  428. {
  429. dwTransOld = dwTransacted;
  430. dwTransacted = STGM_DIRECT;
  431. dwRDWOld = dwRootDenyWrite;
  432. dwRootDenyWrite = STGM_SHARE_EXCLUSIVE;
  433. }
  434. // Forces transacted mode similarly to ForceDirect
  435. void ForceTransacted(void)
  436. {
  437. dwTransOld = dwTransacted;
  438. dwRDWOld = dwRootDenyWrite;
  439. dwTransacted = STGM_TRANSACTED;
  440. }
  441. // Returns to the original mode after a ForceDirect or ForceTransacted
  442. void Unforce(void)
  443. {
  444. dwTransacted = dwTransOld;
  445. dwRootDenyWrite = dwRDWOld;
  446. }
  447. // Equality for FILETIME
  448. BOOL IsEqualTime(FILETIME ttTime, FILETIME ttCheck)
  449. {
  450. // File times can be off by as much as 2 seconds due to FAT rounding
  451. LONGLONG tmTime = *(LONGLONG *)&ttTime;
  452. LONGLONG tmCheck = *(LONGLONG *)&ttCheck;
  453. LONGLONG tmDelta = tmTime - tmCheck;
  454. return tmDelta < 20000000i64 && tmDelta > -2i64 ;
  455. }
  456. // Get a fully qualified path for a file name
  457. void GetFullPath(OLECHAR *file, OLECHAR *path)
  458. {
  459. #ifndef UNICODE
  460. char buf[_MAX_PATH];
  461. OFSTRUCT of;
  462. OLETOA(file, buf, _MAX_PATH);
  463. OpenFile(buf, &of, OF_PARSE);
  464. ATOOLE((char *)of.szPathName, path, _MAX_PATH);
  465. #else
  466. OLECHAR *ptcsFile;
  467. GetFullPathName(file, _MAX_PATH, path, &ptcsFile);
  468. #endif
  469. }
  470. // Memory helper functions
  471. HRESULT drtMemAlloc(ULONG ulcb, void **ppv)
  472. {
  473. HRESULT hr;
  474. IMalloc *pMalloc = NULL;
  475. if (SUCCEEDED(DfGetScode(hr = CoGetMalloc(MEMCTX_TASK, &pMalloc))))
  476. {
  477. *ppv = pMalloc->Alloc(ulcb);
  478. pMalloc->Release();
  479. if (*ppv == NULL)
  480. return ResultFromScode(E_OUTOFMEMORY);
  481. }
  482. return hr;
  483. }
  484. void drtMemFree(void *pv)
  485. {
  486. IMalloc FAR* pMalloc;
  487. if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
  488. {
  489. pMalloc->Free(pv);
  490. pMalloc->Release();
  491. }
  492. }
  493. #pragma pack(1)
  494. struct SplitGuid
  495. {
  496. DWORD dw1;
  497. WORD w1;
  498. WORD w2;
  499. BYTE b[8];
  500. };
  501. #pragma pack()
  502. char *GuidText(GUID const *pguid)
  503. {
  504. static char buf[39];
  505. SplitGuid *psg = (SplitGuid *)pguid;
  506. sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  507. psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
  508. psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
  509. return buf;
  510. }