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.

571 lines
14 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. commonnt.c
  5. Abstract:
  6. Common functionality between various parts of GUI mode-side processing.
  7. The routines in this library are shared only by other LIBs in the
  8. w95upgnt tree.
  9. Author:
  10. Jim Schmidt (jimschm) 18-Aug-1998
  11. Revision History:
  12. Name (alias) Date Description
  13. --*/
  14. #include "pch.h"
  15. #define DBG_DATAFILTER "Data Filter"
  16. BOOL
  17. WINAPI
  18. CommonNt_Entry (
  19. IN HINSTANCE Instance,
  20. IN DWORD Reason,
  21. IN PVOID lpv
  22. )
  23. /*++
  24. Routine Description:
  25. CommonNt_Entry is a DllMain-like init funciton, called by w95upgnt\dll.
  26. This function is called at process attach and detach.
  27. Arguments:
  28. Instance - (OS-supplied) instance handle for the DLL
  29. Reason - (OS-supplied) indicates attach or detatch from process or
  30. thread
  31. lpv - unused
  32. Return Value:
  33. Return value is always TRUE (indicating successful init).
  34. --*/
  35. {
  36. switch (Reason) {
  37. case DLL_PROCESS_ATTACH:
  38. // Nothing to do...
  39. break;
  40. case DLL_PROCESS_DETACH:
  41. // Nothing to do...
  42. break;
  43. }
  44. return TRUE;
  45. }
  46. typedef enum {
  47. STATE_NO_PATH,
  48. STATE_PATH_FOUND,
  49. STATE_IN_PATH,
  50. STATE_PATH_CHANGED,
  51. STATE_PATH_DELETED,
  52. STATE_LONG_PATH_CHANGED,
  53. STATE_SHORT_PATH_CHANGED,
  54. STATE_RETURN_PATH
  55. } SCANSTATE;
  56. BOOL
  57. pIsPathSeparator (
  58. CHARTYPE ch
  59. )
  60. {
  61. return ch == 0 ||
  62. ch == TEXT(',') ||
  63. ch == TEXT(';') ||
  64. _istspace (ch) != 0;
  65. }
  66. BOOL
  67. pIsValidPathCharacter (
  68. CHARTYPE ch
  69. )
  70. {
  71. if (_istalnum (ch)) {
  72. return TRUE;
  73. }
  74. if (ch == TEXT(',') ||
  75. ch == TEXT(';') ||
  76. ch == TEXT('\"') ||
  77. ch == TEXT('<') ||
  78. ch == TEXT('>') ||
  79. ch == TEXT('|') ||
  80. ch == TEXT('?') ||
  81. ch == TEXT('*')
  82. ) {
  83. return FALSE;
  84. }
  85. return TRUE;
  86. }
  87. CONVERTPATH_RC
  88. pGetReplacementPath (
  89. IN PCTSTR DataStart,
  90. IN PCTSTR Pos,
  91. OUT PCTSTR *OldStart,
  92. OUT PCTSTR *OldEnd,
  93. OUT PTSTR ReplacementStr
  94. )
  95. {
  96. CONVERTPATH_RC rc = CONVERTPATH_NOT_REMAPPED;
  97. SCANSTATE State;
  98. BOOL DontIncrement;
  99. PCTSTR OrgStart = NULL;
  100. TCHAR PathBuffer[MAX_TCHAR_PATH + 2];
  101. TCHAR RenamedFile[MAX_TCHAR_PATH];
  102. PTSTR PathBufferRoot = NULL;
  103. PTSTR PathBufferPtr = NULL;
  104. CONVERTPATH_RC ConvertCode = 0;
  105. BOOL ShortPath = FALSE;
  106. BOOL QuotesOn = FALSE;
  107. BOOL Done = FALSE;
  108. BOOL OrgPathHasSepChar = FALSE;
  109. BOOL NeedQuotes = FALSE;
  110. BOOL PathSepChar;
  111. PCTSTR p;
  112. BOOL QuotesOnColumn = FALSE;
  113. PCTSTR LastPathPosition = NULL;
  114. State = STATE_NO_PATH;
  115. PathBuffer[0] = TEXT('\"');
  116. //
  117. // Scan string of Pos for command line
  118. //
  119. while (!Done) {
  120. DontIncrement = FALSE;
  121. switch (State) {
  122. case STATE_NO_PATH:
  123. if (Pos[0] == 0) {
  124. Done = TRUE;
  125. break;
  126. }
  127. if (Pos[1] == TEXT(':') && Pos[2] == TEXT('\\')) {
  128. if (_istalpha (Pos[0])) {
  129. QuotesOn = FALSE;
  130. State = STATE_PATH_FOUND;
  131. DontIncrement = TRUE;
  132. }
  133. } else if (Pos[0] == TEXT('\"')) {
  134. if (_istalpha (Pos[1]) && Pos[2] == TEXT(':') && Pos[3] == TEXT('\\')) {
  135. QuotesOn = TRUE;
  136. State = STATE_PATH_FOUND;
  137. }
  138. }
  139. break;
  140. case STATE_PATH_FOUND:
  141. //
  142. // Initialize path attributes
  143. //
  144. QuotesOnColumn = QuotesOn;
  145. LastPathPosition = Pos;
  146. OrgStart = Pos;
  147. PathBufferRoot = &PathBuffer[1];
  148. PathBufferRoot[0] = Pos[0];
  149. PathBufferRoot[1] = Pos[1];
  150. PathBufferPtr = &PathBufferRoot[2];
  151. Pos = &Pos[2];
  152. ShortPath = FALSE;
  153. OrgPathHasSepChar = FALSE;
  154. State = STATE_IN_PATH;
  155. DontIncrement = TRUE;
  156. break;
  157. case STATE_IN_PATH:
  158. //
  159. // Is this a closing quote? If so, look for replacement path
  160. // and fail entire string if it's not replaced.
  161. //
  162. if (Pos[0] == TEXT(':')) {
  163. //
  164. // bogus. This cannot be a path, it has two ':' characters
  165. //
  166. Pos = _tcsdec (LastPathPosition, Pos);
  167. if (Pos) {
  168. Pos = _tcsdec (LastPathPosition, Pos);
  169. if (Pos) {
  170. if (Pos[0] == TEXT('\"')) {
  171. Pos = NULL;
  172. }
  173. }
  174. }
  175. if (!Pos) {
  176. Pos = LastPathPosition;
  177. QuotesOn = QuotesOnColumn;
  178. }
  179. State = STATE_NO_PATH;
  180. break;
  181. }
  182. if (QuotesOn && *Pos == TEXT('\"')) {
  183. *PathBufferPtr = 0;
  184. ConvertCode = ConvertWin9xPath (PathBufferRoot);
  185. if (ConvertCode != CONVERTPATH_NOT_REMAPPED) {
  186. State = STATE_PATH_CHANGED;
  187. DontIncrement = TRUE;
  188. break;
  189. }
  190. State = STATE_NO_PATH;
  191. break;
  192. }
  193. //
  194. // Is this a path separator? If so, look in memdb for replacement path.
  195. //
  196. if (Pos[0] == L'\\') {
  197. PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos + 1));
  198. } else {
  199. PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos));
  200. }
  201. if (PathSepChar) {
  202. *PathBufferPtr = 0;
  203. ConvertCode = ConvertWin9xPath (PathBufferRoot);
  204. if (ConvertCode != CONVERTPATH_NOT_REMAPPED) {
  205. State = STATE_PATH_CHANGED;
  206. DontIncrement = TRUE;
  207. break;
  208. }
  209. }
  210. //
  211. // Check for end of data
  212. //
  213. if (Pos[0] == 0) {
  214. Done = TRUE;
  215. break;
  216. }
  217. //
  218. // Copy path character to buffer, break if we exceed max path length
  219. //
  220. *PathBufferPtr = *Pos;
  221. PathBufferPtr = _tcsinc (PathBufferPtr);
  222. if (PathBufferPtr == PathBufferRoot + MAX_TCHAR_PATH) {
  223. Pos = OrgStart;
  224. State = STATE_NO_PATH;
  225. break;
  226. }
  227. //
  228. // Test for short path
  229. //
  230. if (*Pos == TEXT('~')) {
  231. ShortPath = TRUE;
  232. }
  233. OrgPathHasSepChar |= PathSepChar;
  234. break;
  235. case STATE_PATH_CHANGED:
  236. if (ConvertCode == CONVERTPATH_DELETED) {
  237. State = STATE_PATH_DELETED;
  238. } else if (ShortPath) {
  239. State = STATE_SHORT_PATH_CHANGED;
  240. } else {
  241. State = STATE_LONG_PATH_CHANGED;
  242. }
  243. //
  244. // If replacement has introduced a path separator, set the
  245. // NeedQuotes flag. Quotes will later be added if the path
  246. // is only part of the complete string.
  247. //
  248. NeedQuotes = FALSE;
  249. if (!OrgPathHasSepChar) {
  250. for (p = PathBufferRoot ; *p ; p = _tcsinc (p)) {
  251. if (pIsPathSeparator ((CHARTYPE) _tcsnextc (p))) {
  252. NeedQuotes = TRUE;
  253. break;
  254. }
  255. }
  256. }
  257. DontIncrement = TRUE;
  258. break;
  259. case STATE_PATH_DELETED:
  260. State = STATE_RETURN_PATH;
  261. DontIncrement = TRUE;
  262. break;
  263. case STATE_SHORT_PATH_CHANGED:
  264. if (OurGetShortPathName (PathBufferRoot, RenamedFile, MAX_TCHAR_PATH)) {
  265. PathBufferRoot = RenamedFile;
  266. }
  267. State = STATE_RETURN_PATH;
  268. DontIncrement = TRUE;
  269. break;
  270. case STATE_LONG_PATH_CHANGED:
  271. if (!QuotesOn && NeedQuotes) {
  272. if (OrgStart != DataStart || Pos[0] != 0) {
  273. PathBufferPtr = _tcschr (PathBufferRoot, 0);
  274. PathBufferPtr[0] = TEXT('\"');
  275. PathBufferPtr[1] = 0;
  276. PathBufferRoot = PathBuffer;
  277. }
  278. }
  279. State = STATE_RETURN_PATH;
  280. DontIncrement = TRUE;
  281. break;
  282. case STATE_RETURN_PATH:
  283. rc = ConvertCode;
  284. StringCopy (ReplacementStr, PathBufferRoot);
  285. *OldStart = OrgStart;
  286. *OldEnd = Pos;
  287. Done = TRUE;
  288. break;
  289. }
  290. if (!DontIncrement) {
  291. Pos = _tcsinc (Pos);
  292. }
  293. }
  294. return rc;
  295. }
  296. BOOL
  297. ConvertWin9xCmdLine (
  298. IN OUT PTSTR CmdLine, // MAX_CMDLINE buffer
  299. IN PCTSTR ObjectForDbgMsg, OPTIONAL
  300. OUT PBOOL PointsToDeletedItem OPTIONAL
  301. )
  302. {
  303. TCHAR NewCmdLine[MAX_CMDLINE];
  304. TCHAR NewPathBuffer[MAX_TCHAR_PATH];
  305. PCTSTR CmdLineStart;
  306. PCTSTR ReplaceStart;
  307. PCTSTR ExtraParamsStart;
  308. CONVERTPATH_RC ConvertCode;
  309. PTSTR EndOfNewCmdLine;
  310. UINT End = 0;
  311. BOOL NewCmdLineFlag = FALSE;
  312. INT Bytes;
  313. #ifdef DEBUG
  314. TCHAR OriginalCmdLine[MAX_CMDLINE];
  315. StringCopy (OriginalCmdLine, CmdLine);
  316. #endif
  317. if (PointsToDeletedItem) {
  318. *PointsToDeletedItem = FALSE;
  319. }
  320. *NewCmdLine = 0;
  321. ExtraParamsStart = CmdLine;
  322. EndOfNewCmdLine = NewCmdLine;
  323. for(;;) {
  324. CmdLineStart = ExtraParamsStart;
  325. //
  326. // We must test for a command line argument that has quotes or
  327. // doesn't need quotes, and then test for an argument that needs
  328. // quotes but doesn't have them.
  329. //
  330. ConvertCode = pGetReplacementPath (
  331. CmdLine,
  332. CmdLineStart,
  333. &ReplaceStart,
  334. &ExtraParamsStart,
  335. NewPathBuffer
  336. );
  337. if (ConvertCode == CONVERTPATH_NOT_REMAPPED) {
  338. //
  339. // Rest of command line does not have changed files
  340. //
  341. break;
  342. }
  343. //
  344. // If a command line was found, we must replace the text between
  345. // ReplaceStart and ExtraParamsStart with NewPathBuffer. To do this,
  346. // we copy the unchanged portion (from CmdLineStart to ReplaceStart)
  347. // to the caller's buffer, and append the replacement text. The
  348. // search continues, searching the rest of the command line specified
  349. // by ExtraParamsStart.
  350. //
  351. if (ConvertCode == CONVERTPATH_DELETED && PointsToDeletedItem) {
  352. *PointsToDeletedItem = TRUE;
  353. }
  354. if (ObjectForDbgMsg) {
  355. DEBUGMSG_IF ((
  356. ConvertCode == CONVERTPATH_DELETED,
  357. DBG_WARNING,
  358. "%s still points to the deleted Win9x file %s (command line: %s).",
  359. ObjectForDbgMsg,
  360. NewPathBuffer,
  361. OriginalCmdLine
  362. ));
  363. }
  364. //
  365. // Path has changed, so we replace the path in the command line.
  366. //
  367. End = ((PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine) +
  368. ((PBYTE) ReplaceStart - (PBYTE) CmdLineStart) +
  369. SizeOfString (NewPathBuffer);
  370. if (End > sizeof (NewCmdLine)) {
  371. LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun - aborting"));
  372. return FALSE;
  373. }
  374. if (ReplaceStart > CmdLineStart) {
  375. StringCopyAB (EndOfNewCmdLine, CmdLineStart, ReplaceStart);
  376. }
  377. EndOfNewCmdLine = _tcsappend (EndOfNewCmdLine, NewPathBuffer);
  378. NewCmdLineFlag |= (ConvertCode == CONVERTPATH_REMAPPED);
  379. }
  380. if (NewCmdLineFlag) {
  381. //
  382. // We have changed the command line, so complete the processing.
  383. //
  384. if (ExtraParamsStart && *ExtraParamsStart) {
  385. End = (PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine + SizeOfString (ExtraParamsStart);
  386. if (End > sizeof (NewCmdLine)) {
  387. LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun -- aborting (2)"));
  388. return FALSE;
  389. }
  390. StringCopy (EndOfNewCmdLine, ExtraParamsStart);
  391. }
  392. //
  393. // End is the number of bytes in NewCmdLine
  394. //
  395. Bytes = (INT) End - sizeof(TCHAR);
  396. } else {
  397. //
  398. // No changes yet, initialize Bytes
  399. //
  400. Bytes = (INT) ByteCount (CmdLine);
  401. }
  402. //
  403. // In-place string conversion, first look for a complete match, and when
  404. // that fails, look for a partial match.
  405. //
  406. if (MappingSearchAndReplaceEx (
  407. g_CompleteMatchMap,
  408. NewCmdLineFlag ? NewCmdLine : CmdLine,
  409. NewCmdLine,
  410. Bytes,
  411. NULL,
  412. sizeof (NewCmdLine),
  413. STRMAP_COMPLETE_MATCH_ONLY,
  414. NULL,
  415. NULL
  416. )) {
  417. NewCmdLineFlag = TRUE;
  418. } else {
  419. NewCmdLineFlag |= MappingSearchAndReplaceEx (
  420. g_SubStringMap,
  421. NewCmdLineFlag ? NewCmdLine : CmdLine,
  422. NewCmdLine,
  423. Bytes,
  424. NULL,
  425. sizeof (NewCmdLine),
  426. STRMAP_ANY_MATCH,
  427. NULL,
  428. NULL
  429. );
  430. }
  431. if (NewCmdLineFlag) {
  432. DEBUGMSG ((
  433. DBG_DATAFILTER,
  434. "Command line %s was modified to %s",
  435. OriginalCmdLine,
  436. NewCmdLine
  437. ));
  438. StringCopy (CmdLine, NewCmdLine);
  439. }
  440. return NewCmdLineFlag;
  441. }