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.

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