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.

627 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. explorer.c
  5. Abstract:
  6. Explorer-related converters
  7. Explorer-related conversion functions needed to convert
  8. MRU lists and other structures are implemented here.
  9. Author:
  10. Jim Schmidt (jimschm) 9-Aug-1996
  11. Revision History:
  12. Calin Negreanu (calinn) 04-Mar-1998 Minor bug in ConvertCommandToCmd
  13. Jim Schmidt (jimschm) 20-Feb-1998 Added ValFn_ModuleUsage
  14. --*/
  15. #include "pch.h"
  16. #include "rulehlprp.h"
  17. #include <mbstring.h>
  18. #include <shlobj.h>
  19. #define S_OWNER TEXT(".Owner")
  20. typedef struct {
  21. // Link structure
  22. WORD wSize;
  23. //ITEMIDLIST idl; // variable-length struct
  24. // String, plus three bytes appended to struct
  25. } LINKSTRUCT, *PLINKSTRUCT;
  26. //
  27. // This list of extensions is ordered in the way Win9x processes extensions
  28. //
  29. static PCTSTR g_RunMruExtensions[] = {
  30. TEXT("PIF"),
  31. TEXT("COM"),
  32. TEXT("EXE"),
  33. TEXT("BAT"),
  34. TEXT("LNK"),
  35. NULL
  36. };
  37. BOOL
  38. ValFn_ConvertRecentDocsMRU (
  39. IN PDATAOBJECT ObPtr
  40. )
  41. {
  42. LPSTR str, strEnd;
  43. PLINKSTRUCT pls95, plsNT;
  44. DWORD dwStrSize, dwSize;
  45. DWORD dwNewSize, dwLinkSize;
  46. PWSTR wstr, wstrEnd;
  47. BOOL b;
  48. // Skip MRUList
  49. MYASSERT(ObPtr->ValueName);
  50. if (StringIMatch (ObPtr->ValueName, TEXT("MRUList"))) {
  51. return TRUE;
  52. }
  53. // Calculate all the pointers to this nasty struct
  54. str = (LPSTR) ObPtr->Value.Buffer;
  55. strEnd = GetEndOfStringA (str);
  56. strEnd = _mbsinc (strEnd);
  57. dwStrSize = (DWORD) strEnd - (DWORD) str;
  58. pls95 = (PLINKSTRUCT) strEnd;
  59. dwLinkSize = pls95->wSize + sizeof (WORD);
  60. dwSize = dwStrSize + dwLinkSize;
  61. // Make sure the key is the struct we expect
  62. if (dwSize != ObPtr->Value.Size) {
  63. SetLastError (ERROR_SUCCESS); // ignore this error
  64. DEBUGMSG ((
  65. DBG_NAUSEA,
  66. "ValFn_ConvertRecentDocsMRU failed because size was not correct. "
  67. "%u should have been %u",
  68. ObPtr->Value.Size,
  69. dwSize
  70. ));
  71. return FALSE;
  72. }
  73. // Calc UNICODE size & alloc a new buffer
  74. dwNewSize = (LcharCountA (str) + 1) * sizeof (WCHAR);
  75. dwNewSize += dwLinkSize;
  76. wstr = (PWSTR) PoolMemGetMemory (g_TempPool, dwNewSize);
  77. if (!wstr) {
  78. return FALSE;
  79. }
  80. // Fill new buffer with converted struct
  81. MultiByteToWideChar (OurGetACP(),
  82. 0,
  83. str,
  84. -1,
  85. wstr,
  86. dwNewSize);
  87. wstrEnd = GetEndOfStringW (wstr) + 1;
  88. plsNT = (PLINKSTRUCT) ((LPBYTE) wstr + ((DWORD) wstrEnd - (DWORD) wstr));
  89. CopyMemory (plsNT, pls95, dwLinkSize);
  90. b = ReplaceValue (ObPtr, (LPBYTE) wstr, dwNewSize);
  91. PoolMemReleaseMemory (g_TempPool, wstr);
  92. return b;
  93. }
  94. BOOL
  95. ConvertCommandToCmd (
  96. PCTSTR InputLine,
  97. PTSTR CmdLine
  98. )
  99. {
  100. PCTSTR p, q;
  101. PCTSTR end;
  102. PTSTR dest;
  103. BOOL QuoteMode;
  104. TCHAR Redirect[256];
  105. int ParamsToCopy = 0;
  106. int ParamsToSkip = 0;
  107. int ParamNum;
  108. p = InputLine;
  109. //
  110. // Parse command line
  111. //
  112. p += 7; // skip "command"
  113. if (StringIMatchTcharCount (p, TEXT(".com"), 4)) {
  114. p += 4;
  115. }
  116. if (_tcsnextc (p) == TEXT('\\') || !(*p)) {
  117. //
  118. // no params case
  119. //
  120. wsprintf (CmdLine, TEXT("cmd%s"), p);
  121. } else if (*p == TEXT(' ')) {
  122. //
  123. // Extract all params
  124. //
  125. StringCopy (CmdLine, TEXT("cmd.exe"));
  126. Redirect[0] = 0;
  127. ParamNum = 0;
  128. do {
  129. // Skip leading spaces
  130. p = SkipSpace (p);
  131. // Command line option
  132. if (*p == TEXT('-') || *p == TEXT('/')) {
  133. ParamsToCopy = 0;
  134. ParamsToSkip = 0;
  135. // Test multi-character options
  136. if (StringIMatchTcharCount (&p[1], TEXT("msg"), 3) ||
  137. StringIMatchTcharCount (&p[1], TEXT("low"), 3)
  138. ) {
  139. // These are obsolete options
  140. ParamsToSkip = 1;
  141. }
  142. // Test single-character options
  143. else {
  144. switch (_totlower (p[1])) {
  145. case 'c':
  146. case 'k':
  147. // These are compatible options - copy to command line
  148. ParamsToCopy = -1;
  149. break;
  150. case '>':
  151. case '<':
  152. // Redirection is supported
  153. ParamsToCopy = -1; // rest of line
  154. break;
  155. case 'e':
  156. case 'l':
  157. case 'u':
  158. case 'p':
  159. // These are obsolete options
  160. ParamsToSkip = 1;
  161. break;
  162. case 'y':
  163. // These options really require command.com, not cmd.exe
  164. return FALSE;
  165. default:
  166. ParamsToSkip = 1;
  167. break;
  168. }
  169. }
  170. } /* if p is a dash or slash */
  171. // Else it's a directory containing command.com, device redirection or syntax error
  172. else {
  173. if (ParamNum == 0) {
  174. //
  175. // Directory containing command.com - obsolete
  176. //
  177. ParamsToCopy = 0;
  178. ParamsToSkip = 1;
  179. } else if (ParamNum == 1) {
  180. //
  181. // Extract redirection command
  182. //
  183. ParamNum++;
  184. end = p;
  185. while (*end && _tcsnextc (end) != TEXT(' ') && _tcsnextc (end) != TEXT('\\')) {
  186. end = _tcsinc (end);
  187. }
  188. StringCopyAB (Redirect, p, end);
  189. p = end;
  190. } else {
  191. // Unexpected, perhaps a syntax error -- leave this line alone
  192. return FALSE;
  193. }
  194. }
  195. // Copy rest of line
  196. if (ParamsToCopy == -1) {
  197. if (CmdLine[0]) {
  198. StringCat (CmdLine, TEXT(" "));
  199. }
  200. StringCat (CmdLine, p);
  201. p = GetEndOfString (p);
  202. }
  203. // Copy one or more params
  204. else {
  205. while (ParamsToCopy > 0) {
  206. QuoteMode = FALSE;
  207. q = p;
  208. while (*q) {
  209. if (_tcsnextc (q) == TEXT('\"')) {
  210. QuoteMode = !QuoteMode;
  211. } else if (!QuoteMode && _tcsnextc (q) == TEXT(' ')) {
  212. break;
  213. }
  214. q = _tcsinc (q);
  215. }
  216. ParamNum++;
  217. if (CmdLine[0]) {
  218. StringCat (CmdLine, TEXT(" "));
  219. }
  220. StringCopyAB (GetEndOfString (CmdLine), p, q);
  221. p = q;
  222. ParamsToCopy--;
  223. }
  224. }
  225. while (ParamsToSkip > 0) {
  226. QuoteMode = FALSE;
  227. q = p;
  228. while (*q) {
  229. if (_tcsnextc (q) == TEXT('\"')) {
  230. QuoteMode = !QuoteMode;
  231. } else if (!QuoteMode && _tcsnextc (q) == TEXT(' ')) {
  232. break;
  233. }
  234. q = _tcsinc (q);
  235. }
  236. ParamNum++;
  237. p = q;
  238. ParamsToSkip--;
  239. }
  240. } while (*p);
  241. if (Redirect[0]) {
  242. TCHAR WackNum[8];
  243. // Look for \1 in cmd line (made by Explorer)
  244. WackNum[0] = 0;
  245. dest = _tcsrchr (CmdLine, TEXT('\\'));
  246. if (*dest) {
  247. if (_istdigit ((CHARTYPE) _tcsnextc (_tcsinc (dest)))) {
  248. if (!(*(_tcsinc (_tcsinc (dest))))) {
  249. StringCopy (WackNum, dest);
  250. *dest = 0;
  251. }
  252. }
  253. }
  254. wsprintf (GetEndOfString (CmdLine), TEXT(" >%s <%s%s"),
  255. Redirect, Redirect, WackNum);
  256. }
  257. } else {
  258. //
  259. // not command or command.com
  260. //
  261. return FALSE;
  262. }
  263. return TRUE;
  264. }
  265. BOOL
  266. ValFn_ConvertRunMRU (
  267. IN PDATAOBJECT ObPtr
  268. )
  269. {
  270. PCTSTR p;
  271. TCHAR CmdLine[1024];
  272. GROWBUFFER NewCmdLine = GROWBUF_INIT;
  273. GROWBUFFER GrowBuf = GROWBUF_INIT;
  274. PCMDLINE ParsedCmdLine;
  275. UINT u;
  276. DWORD Status;
  277. PCTSTR NewPath;
  278. BOOL Quotes;
  279. BOOL b = TRUE;
  280. PTSTR CmdLineCopy;
  281. PTSTR WackOne;
  282. PTSTR Dot;
  283. PTSTR Ext;
  284. INT i;
  285. PCTSTR MatchingArg;
  286. // Skip MRUList
  287. MYASSERT(ObPtr->ValueName);
  288. if (StringIMatch (ObPtr->ValueName, TEXT("MRUList"))) {
  289. return TRUE;
  290. }
  291. //
  292. // Convert command to cmd
  293. //
  294. p = (PCTSTR) ObPtr->Value.Buffer;
  295. if (StringIMatchTcharCount (p, TEXT("command"), 7)) {
  296. //
  297. // Convert command.com to cmd.exe
  298. //
  299. if (ConvertCommandToCmd (p, CmdLine)) {
  300. // If able to convert, update the line
  301. b = ReplaceValueWithString (ObPtr, CmdLine);
  302. }
  303. } else {
  304. //
  305. // Look at each arg for paths to moved files, and fix them.
  306. //
  307. CmdLineCopy = DuplicateText ((PCTSTR) ObPtr->Value.Buffer);
  308. WackOne = _tcsrchr (CmdLineCopy, TEXT('\\'));
  309. if (WackOne && WackOne[1] == TEXT('1') && WackOne[2] == 0) {
  310. *WackOne = 0;
  311. } else {
  312. WackOne = NULL;
  313. }
  314. ParsedCmdLine = ParseCmdLine (CmdLineCopy, &GrowBuf);
  315. if (ParsedCmdLine) {
  316. for (u = 0 ; u < ParsedCmdLine->ArgCount ; u++) {
  317. if (u) {
  318. GrowBufAppendString (&NewCmdLine, TEXT(" "));
  319. }
  320. MatchingArg = ParsedCmdLine->Args[u].CleanedUpArg;
  321. if (!_tcschr (ParsedCmdLine->Args[u].OriginalArg, TEXT('\\'))) {
  322. Status = FILESTATUS_UNCHANGED;
  323. } else {
  324. Status = GetFileStatusOnNt (MatchingArg);
  325. if ((Status & FILESTATUS_MOVED) == 0) {
  326. //
  327. // If the true path didn't match, try various extensions
  328. //
  329. _tcssafecpy (CmdLine, MatchingArg, (sizeof (CmdLine) - 10) / sizeof (TCHAR));
  330. Dot = _tcsrchr (CmdLine, TEXT('.'));
  331. if (!Dot || _tcschr (Dot, TEXT('\\'))) {
  332. Dot = GetEndOfString (CmdLine);
  333. }
  334. *Dot = TEXT('.');
  335. Ext = Dot + 1;
  336. MatchingArg = CmdLine;
  337. for (i = 0 ; g_RunMruExtensions[i] ; i++) {
  338. StringCopy (Ext, g_RunMruExtensions[i]);
  339. Status = GetFileStatusOnNt (MatchingArg);
  340. if (Status & FILESTATUS_MOVED) {
  341. break;
  342. }
  343. }
  344. }
  345. }
  346. if (Status & FILESTATUS_MOVED) {
  347. NewPath = GetPathStringOnNt (MatchingArg);
  348. Quotes = FALSE;
  349. if (_tcschr (NewPath, TEXT('\"'))) {
  350. Quotes = TRUE;
  351. GrowBufAppendString (&NewCmdLine, TEXT("\""));
  352. }
  353. GrowBufAppendString (&NewCmdLine, NewPath);
  354. FreePathStringW (NewPath);
  355. } else {
  356. GrowBufAppendString (&NewCmdLine, ParsedCmdLine->Args[u].OriginalArg);
  357. }
  358. }
  359. if (WackOne) {
  360. GrowBufAppendString (&NewCmdLine, TEXT("\\1"));
  361. }
  362. b = ReplaceValueWithString (ObPtr, (PCTSTR) NewCmdLine.Buf);
  363. FreeGrowBuffer (&NewCmdLine);
  364. }
  365. FreeText (CmdLineCopy);
  366. }
  367. FreeGrowBuffer (&GrowBuf);
  368. return b;
  369. }
  370. BOOL
  371. ValFn_ModuleUsage (
  372. IN OUT PDATAOBJECT ObPtr
  373. )
  374. /*++
  375. Routine Description:
  376. This routine uses the RuleHlpr_ConvertRegVal simplification routine. See
  377. rulehlpr.c for details. The simplification routine does almost all the work
  378. for us; all we need to do is update the value.
  379. ValFn_ModuleUsage determines if the registry object should be changed,
  380. so it is merged with the NT settings. The algorithm is:
  381. 1. Get GUID and file name from object
  382. 2. If file name is already registred, add another value entry
  383. 3. If file name is not already registred, add it and make an .Owner entry
  384. Arguments:
  385. ObPtr - Specifies the Win95 data object as specified in wkstamig.inf,
  386. [Win9x Data Conversion] section. The object value is then modified.
  387. After returning, the merge code then copies the data to the NT
  388. destination, which has a new location (specified in wkstamig.inf,
  389. [Map Win9x to WinNT] section).
  390. Return Value:
  391. Tri-state:
  392. TRUE to allow merge code to continue processing (it writes the value)
  393. FALSE and last error == ERROR_SUCCESS to continue, but skip the write
  394. FALSE and last error != ERROR_SUCCESS if an error occurred
  395. --*/
  396. {
  397. TCHAR FileName[MAX_TCHAR_PATH];
  398. TCHAR Guid[64];
  399. PTSTR p;
  400. TCHAR KeyStr[MAX_REGISTRY_KEY];
  401. HKEY Key;
  402. PCTSTR Data;
  403. //
  404. // Skip no-value keys
  405. //
  406. if (!IsObjectRegistryKeyAndVal (ObPtr) ||
  407. !IsRegistryTypeSpecified (ObPtr) ||
  408. !ObPtr->Value.Size
  409. ) {
  410. SetLastError (ERROR_SUCCESS);
  411. return FALSE;
  412. }
  413. //
  414. // Step 1: Extract GUID and file name
  415. //
  416. // File name is the subkey name
  417. StackStringCopy (FileName, ObPtr->KeyPtr->KeyString);
  418. // Convert backslashes to foreslashes
  419. p = _tcschr (FileName, TEXT('\\'));
  420. while (p) {
  421. *p = TEXT('/');
  422. p = _tcschr (_tcsinc (p), TEXT('\\'));
  423. }
  424. // GUID is the value
  425. if (ObPtr->Type != REG_SZ && ObPtr->Type != REG_EXPAND_SZ) {
  426. SetLastError (ERROR_SUCCESS);
  427. DEBUGMSG ((DBG_WARNING, "Skipping non-string value for key %s", FileName));
  428. return FALSE;
  429. }
  430. _tcssafecpy (Guid, ObPtr->ValueName, sizeof(Guid)/sizeof(Guid[0]));
  431. // If Guid is .Owner, then GUID is value data
  432. if (StringIMatch (Guid, S_OWNER)) {
  433. _tcssafecpy (Guid, (PCTSTR) ObPtr->Value.Buffer, sizeof(Guid)/sizeof(Guid[0]));
  434. }
  435. //
  436. // Step 2: Does NT key already exist?
  437. //
  438. wsprintf (
  439. KeyStr,
  440. TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ModuleUsage\\%s"),
  441. FileName
  442. );
  443. Key = OpenRegKeyStr (KeyStr);
  444. if (Key) {
  445. //
  446. // Yes, look for .Owner
  447. //
  448. Data = GetRegValueString (Key, S_OWNER);
  449. if (!Data) {
  450. //
  451. // .Owner does not exist, assume key is empty, and re-create it
  452. //
  453. CloseRegKey (Key);
  454. Key = NULL;
  455. } else {
  456. MemFree (g_hHeap, 0, Data);
  457. }
  458. }
  459. //
  460. // Step 3: If NT key does not exist or has no owner, create the initial
  461. // usage reference, otherwise add non-owner reference entry
  462. //
  463. if (!Key) {
  464. //
  465. // Key does not exist or does not have owner. Create it.
  466. //
  467. Key = CreateRegKeyStr (KeyStr);
  468. if (!Key) {
  469. LOG ((LOG_ERROR, "Can't create %s", KeyStr));
  470. SetLastError (ERROR_SUCCESS);
  471. return FALSE;
  472. }
  473. // Add .Owner entry
  474. RegSetValueEx (Key, S_OWNER, 0, REG_SZ, (PBYTE) Guid, SizeOfString (Guid));
  475. } else {
  476. //
  477. // .Owner does exist, just add GUID as a value (with no value data)
  478. //
  479. RegSetValueEx (Key, Guid, 0, REG_SZ, (PBYTE) S_EMPTY, sizeof (TCHAR));
  480. }
  481. CloseRegKey (Key);
  482. SetLastError (ERROR_SUCCESS);
  483. return FALSE;
  484. }