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.

594 lines
14 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. exceppk.c
  5. Abstract:
  6. Implementation of exception packages processing functions.
  7. Author:
  8. Marian Trandafir (mariant) 27-Nov-2000
  9. Revision History:
  10. --*/
  11. #include "sfcp.h"
  12. #pragma hdrstop
  13. #include <excppkg.h>
  14. //
  15. // Exception packages processing
  16. //
  17. typedef struct _SFC_EXCEPTION_INFO
  18. {
  19. LIST_ENTRY ListEntry;
  20. GUID guid;
  21. WCHAR InfName[0];
  22. }
  23. SFC_EXCEPTION_INFO, *PSFC_EXCEPTION_INFO;
  24. typedef struct _SFC_EXCEPTION_QUEUE_CONTEXT
  25. {
  26. ULONG ProtectedFilesCount;
  27. ULONG InsertedFilesCount;
  28. PSFC_EXCEPTION_INFO ExcepInfo;
  29. }
  30. SFC_EXCEPTION_QUEUE_CONTEXT, *PSFC_EXCEPTION_QUEUE_CONTEXT;
  31. DWORD_TREE ExceptionTree; // the exception pack files tree
  32. LIST_ENTRY ExceptionInfList; // list of SFC_EXCEPTION_INFO structures
  33. DWORD ExcepPackCount = 0; // the size of the ExcepPackGuids array
  34. LPGUID ExcepPackGuids = NULL; // the array of package GUIDS
  35. //
  36. // this is the exception package directory (\-terminated)
  37. //
  38. static const WCHAR ExceptionPackDir[] = L"%windir%\\RegisteredPackages\\";
  39. VOID
  40. SfcDestroyList(
  41. PLIST_ENTRY ListHead
  42. )
  43. /*++
  44. Routine Description:
  45. Empties a linked list
  46. Arguments:
  47. LiastHead: pointer to the list header
  48. Return Value:
  49. none
  50. --*/
  51. {
  52. PLIST_ENTRY Entry;
  53. for(Entry = ListHead->Flink; Entry != ListHead; )
  54. {
  55. PLIST_ENTRY Flink = Entry->Flink;
  56. MemFree(Entry);
  57. Entry = Flink;
  58. }
  59. InitializeListHead(ListHead);
  60. }
  61. VOID
  62. SfcExceptionInfoInit(
  63. VOID
  64. )
  65. /*++
  66. Routine Description:
  67. Initializes the exception info list and tree
  68. Arguments:
  69. none
  70. Return Value:
  71. none
  72. --*/
  73. {
  74. TreeInit(&ExceptionTree);
  75. InitializeListHead(&ExceptionInfList);
  76. }
  77. VOID
  78. SfcExceptionInfoDestroy(
  79. VOID
  80. )
  81. /*++
  82. Routine Description:
  83. Empties the exception info list and tree.
  84. Arguments:
  85. none
  86. Return Value:
  87. none
  88. --*/
  89. {
  90. TreeDestroy(&ExceptionTree);
  91. SfcDestroyList(&ExceptionInfList);
  92. }
  93. BOOL
  94. ExceptionPackageSetChanged(
  95. VOID
  96. )
  97. /*++
  98. Routine Description:
  99. Checks if the installed exception package set has changed. The routine uses the exception package API
  100. to get the current list of installed exceppack's GUIDs and compares the list with the old one. If the
  101. lists are different, it replaces the old list with the new one.
  102. Arguments:
  103. none
  104. Return Value:
  105. TRUE if the list has changed.
  106. --*/
  107. {
  108. LPGUID NewList = NULL;
  109. DWORD NewCount;
  110. DWORD Error = ERROR_SUCCESS;
  111. BOOL bRet;
  112. if(!SetupQueryRegisteredOsComponentsOrder(&NewCount, NULL))
  113. {
  114. Error = GetLastError();
  115. goto lExit;
  116. }
  117. if(NewCount != 0)
  118. {
  119. NewList = (LPGUID) MemAlloc(NewCount * sizeof(GUID));
  120. if(NULL == NewList)
  121. {
  122. Error = ERROR_NOT_ENOUGH_MEMORY;
  123. goto lExit;
  124. }
  125. if(!SetupQueryRegisteredOsComponentsOrder(&NewCount, NewList))
  126. {
  127. Error = GetLastError();
  128. goto lExit;
  129. }
  130. }
  131. if(ExcepPackCount == NewCount &&
  132. (0 == NewCount || 0 == memcmp(ExcepPackGuids, NewList, NewCount * sizeof(GUID))))
  133. {
  134. bRet = FALSE;
  135. goto lExit;
  136. }
  137. MemFree(ExcepPackGuids);
  138. ExcepPackCount = NewCount;
  139. ExcepPackGuids = NewList;
  140. NewList = NULL;
  141. bRet = TRUE;
  142. lExit:
  143. MemFree(NewList);
  144. //
  145. // if errors occured, delete the old list and try to rebuild the exception info anyway
  146. //
  147. if(Error != ERROR_SUCCESS)
  148. {
  149. DebugPrint1(LVL_MINIMAL, L"Error 0x%08lX occured while reading exception packages info.", Error);
  150. MemFree(ExcepPackGuids);
  151. ExcepPackGuids = NULL;
  152. ExcepPackCount = 0;
  153. bRet = TRUE;
  154. }
  155. return bRet;
  156. }
  157. BOOL
  158. SfcLookupAndInsertExceptionFile(
  159. IN LPCWSTR FilePath,
  160. IN PSFC_EXCEPTION_QUEUE_CONTEXT Context
  161. )
  162. /*++
  163. Routine Description:
  164. Lookup if an exceppack file is protected and, if so, inserts it in the exception search binary tree.
  165. The search key of this tree is the index of the SFC_REGISTRY_VALUE describing the protected file in the
  166. SfcProtectedDllsList array. The context stored in the tree is a pointer to an SFC_EXCEPTION_INFO structure
  167. allocated on the heap and inserted in the ExceptionInfList list.
  168. Arguments:
  169. FilePath: full path to the exception file to be inserted
  170. Context: pointer to the SFC_EXCEPTION_QUEUE_CONTEXT structure that is passed as a setup queue context
  171. Return Value:
  172. TRUE if the file is protected and was inserted in the tree
  173. --*/
  174. {
  175. PNAME_NODE pNode;
  176. UINT_PTR uiIndex;
  177. DWORD dwSize;
  178. WCHAR buffer[MAX_PATH];
  179. ASSERT(FilePath != NULL);
  180. dwSize = wcslen(FilePath);
  181. ASSERT(dwSize != 0 && dwSize < MAX_PATH);
  182. if(dwSize >= MAX_PATH)
  183. {
  184. dwSize = MAX_PATH - 1;
  185. }
  186. RtlCopyMemory(buffer, FilePath, (dwSize + 1) * sizeof(WCHAR));
  187. buffer[MAX_PATH - 1] = 0;
  188. MyLowerString(buffer, dwSize);
  189. pNode = SfcFindProtectedFile(buffer, dwSize * sizeof(WCHAR));
  190. DebugPrint2(LVL_VERBOSE, L"Target file [%s] is %sprotected.", buffer, pNode != NULL ? L"" : L"not ");
  191. if(NULL == pNode)
  192. {
  193. return FALSE;
  194. }
  195. ++(Context->ProtectedFilesCount);
  196. uiIndex = (PSFC_REGISTRY_VALUE) pNode->Context - SfcProtectedDllsList;
  197. ASSERT(uiIndex < SfcProtectedDllCount);
  198. if(NULL == TreeInsert(&ExceptionTree, (ULONG) uiIndex, &Context->ExcepInfo, sizeof(PVOID)))
  199. {
  200. DebugPrint1(LVL_MINIMAL, L"Could not insert file [%s] if the exception tree.", buffer);
  201. return FALSE;
  202. }
  203. ++(Context->InsertedFilesCount);
  204. return TRUE;
  205. }
  206. UINT
  207. SfcExceptionQueueCallback(
  208. PVOID Context,
  209. UINT Notification,
  210. UINT_PTR Param1,
  211. UINT_PTR Param2
  212. )
  213. /*++
  214. Routine Description:
  215. This is the setup queue calback for an exceppack inf. The queue is used to enumerate all
  216. exception files that are installed by the exceppack.
  217. Arguments:
  218. Context: pointer to an SFC_EXCEPTION_QUEUE_CONTEXT structure
  219. Notification: notification code
  220. Param1: first notification parameter
  221. Param2: second notification parameter
  222. Return Value:
  223. Operation code. For installed files, this is always FILEOP_SKIP since we only want to enumerate them
  224. --*/
  225. {
  226. ASSERT(Context != NULL);
  227. ASSERT(SPFILENOTIFY_QUEUESCAN == Notification);
  228. ASSERT(Param1 != 0);
  229. if(SPFILENOTIFY_QUEUESCAN == Notification && Param1 != 0)
  230. {
  231. SfcLookupAndInsertExceptionFile((LPCWSTR) Param1, (PSFC_EXCEPTION_QUEUE_CONTEXT) Context);
  232. }
  233. //
  234. // always continue with the next file
  235. //
  236. return 0;
  237. }
  238. DWORD
  239. SfcBuildExcepPackInfo(
  240. IN const PSETUP_OS_COMPONENT_DATA ComponentData,
  241. IN const PSETUP_OS_EXCEPTION_DATA ExceptionData
  242. )
  243. /*++
  244. Routine Description:
  245. Allocates the exceppack info structure, enumerates and inserts all exceppack protected files and,
  246. if any, inserts exceppack info in the list.
  247. Arguments:
  248. ComponentData, ExceptionData: describe the exceppack as passed to the exceppack enumerator callback.
  249. Return Value:
  250. THe Win32 error code.
  251. --*/
  252. {
  253. HINF hinf = INVALID_HANDLE_VALUE;
  254. HSPFILEQ hfq = INVALID_HANDLE_VALUE;
  255. DWORD dwError = ERROR_SUCCESS;
  256. DWORD dwUnused;
  257. PSFC_EXCEPTION_INFO pExcepInfo = NULL;
  258. SFC_EXCEPTION_QUEUE_CONTEXT Context;
  259. DWORD Size;
  260. LPCWSTR InfName;
  261. InfName = wcsrchr(ExceptionData->ExceptionInfName, L'\\');
  262. ASSERT(InfName != NULL);
  263. if(NULL == InfName)
  264. {
  265. dwError = ERROR_INVALID_DATA;
  266. goto lExit;
  267. }
  268. ++InfName;
  269. Size = wcslen(InfName) + 1;
  270. ASSERT(Size > 1 && Size < MAX_PATH);
  271. Size *= sizeof(WCHAR);
  272. pExcepInfo = (PSFC_EXCEPTION_INFO) MemAlloc(sizeof(SFC_EXCEPTION_INFO) + Size);
  273. if(NULL == pExcepInfo)
  274. {
  275. dwError = ERROR_NOT_ENOUGH_MEMORY;
  276. goto lExit;
  277. }
  278. pExcepInfo->guid = ComponentData->ComponentGuid;
  279. RtlCopyMemory(pExcepInfo->InfName, InfName, Size);
  280. hinf = SetupOpenInfFileW(ExceptionData->ExceptionInfName, NULL, INF_STYLE_WIN4, NULL);
  281. if(INVALID_HANDLE_VALUE == hinf)
  282. {
  283. dwError = GetLastError();
  284. DebugPrint2(LVL_MINIMAL, L"SetupOpenInfFile returned 0x%08lX for [%s]", dwError, ExceptionData->ExceptionInfName);
  285. goto lExit;
  286. }
  287. hfq = SetupOpenFileQueue();
  288. if(INVALID_HANDLE_VALUE == hfq)
  289. {
  290. dwError = GetLastError();
  291. DebugPrint1(LVL_MINIMAL, L"SetupOpenFileQueue returned 0x%08lX.", dwError);
  292. goto lExit;
  293. }
  294. Context.ProtectedFilesCount = Context.InsertedFilesCount = 0;
  295. Context.ExcepInfo = pExcepInfo;
  296. if(!SetupInstallFilesFromInfSectionW(
  297. hinf,
  298. NULL,
  299. hfq,
  300. L"DefaultInstall",
  301. NULL,
  302. 0
  303. ))
  304. {
  305. dwError = GetLastError();
  306. DebugPrint1(LVL_MINIMAL, L"SetupInstallFilesFromInfSectionW returned 0x%08lX.", dwError);
  307. goto lExit;
  308. }
  309. SetupScanFileQueue(
  310. hfq,
  311. SPQ_SCAN_USE_CALLBACK,
  312. NULL,
  313. SfcExceptionQueueCallback,
  314. &Context,
  315. &dwUnused
  316. );
  317. DebugPrint3(
  318. LVL_VERBOSE,
  319. L"Exception package [%s] has %d protected files, of which %d were inserted in the tree.",
  320. ComponentData->FriendlyName,
  321. Context.ProtectedFilesCount,
  322. Context.InsertedFilesCount
  323. );
  324. //
  325. // add the exception info in the list if there was at least one file inserted in the tree
  326. //
  327. if(Context.InsertedFilesCount != 0)
  328. {
  329. InsertTailList(&ExceptionInfList, (PLIST_ENTRY) pExcepInfo);
  330. pExcepInfo = NULL;
  331. }
  332. lExit:
  333. MemFree(pExcepInfo);
  334. if(hfq != INVALID_HANDLE_VALUE)
  335. {
  336. SetupCloseFileQueue(hfq);
  337. }
  338. if(hinf != INVALID_HANDLE_VALUE)
  339. {
  340. SetupCloseInfFile(hinf);
  341. }
  342. return dwError;
  343. }
  344. BOOL CALLBACK SfcExceptionCallback(
  345. IN const PSETUP_OS_COMPONENT_DATA ComponentData,
  346. IN const PSETUP_OS_EXCEPTION_DATA ExceptionData,
  347. IN OUT DWORD_PTR Context
  348. )
  349. /*++
  350. Routine Description:
  351. This is the excceppack enumerator callback. It passes on the excceppack info to SfcBuildExcepPackInfo.
  352. Arguments:
  353. ComponentData, ExceptionData: describe the exceppack
  354. Context: callback context, not used
  355. Return Value:
  356. TRUE to continue the enumeration.
  357. --*/
  358. {
  359. ASSERT(ComponentData->SizeOfStruct == sizeof(*ComponentData));
  360. DebugPrint1(LVL_VERBOSE, L"Building exception info for package [%s]", ComponentData->FriendlyName);
  361. SfcBuildExcepPackInfo(ComponentData, ExceptionData);
  362. //
  363. // continue to scan the remaining packages, regardless of any errors
  364. //
  365. return TRUE;
  366. }
  367. VOID
  368. SfcRefreshExceptionInfo(
  369. VOID
  370. )
  371. /*++
  372. Routine Description:
  373. Verifies if the installed exception pack set has changed and rebuilds exceppack info if necessary.
  374. This is called from different threads so the code protected by a critical section
  375. Arguments:
  376. none
  377. Return Value:
  378. none
  379. --*/
  380. {
  381. RtlEnterCriticalSection(&g_GeneralCS);
  382. if(ExceptionPackageSetChanged())
  383. {
  384. //
  385. // rebuild the entire exception info
  386. //
  387. SfcExceptionInfoDestroy();
  388. if(!SetupEnumerateRegisteredOsComponents(SfcExceptionCallback, 0))
  389. {
  390. DebugPrint1(LVL_MINIMAL, L"SetupEnumerateRegisteredOsComponents returned 0x%08lX.", GetLastError());
  391. }
  392. }
  393. RtlLeaveCriticalSection(&g_GeneralCS);
  394. }
  395. BOOL
  396. SfcGetInfName(
  397. IN PSFC_REGISTRY_VALUE RegVal,
  398. OUT LPWSTR InfName
  399. )
  400. /*++
  401. Routine Description:
  402. Gets the path to the inf file that contains layout info for the protected file described by the RegVal argument.
  403. If the file is part of an installed excceppack, than the path to excceppack inf file is returned. Otherwise,
  404. the function returns the inf path specified in the RegVal argument.
  405. Arguments:
  406. RegVal: pointer to an SFC_REGISTRY_VALUE struct that describes the protected file
  407. InfName: pointer to a buffer of MAX_PATH characters that receives the inf path
  408. Return Value:
  409. TRUE if the file is part of an installed exceppack
  410. --*/
  411. {
  412. PSFC_EXCEPTION_INFO* ppExcepInfo;
  413. UINT_PTR uiIndex;
  414. BOOL bException;
  415. uiIndex = RegVal - SfcProtectedDllsList;
  416. ASSERT(uiIndex < (UINT_PTR) SfcProtectedDllCount);
  417. RtlEnterCriticalSection(&g_GeneralCS);
  418. ppExcepInfo = (PSFC_EXCEPTION_INFO*) TreeFind(&ExceptionTree, (ULONG) uiIndex);
  419. bException = (ppExcepInfo != NULL);
  420. if(bException)
  421. {
  422. PSFC_EXCEPTION_INFO pExcepInfo;
  423. UINT Size;
  424. pExcepInfo = *ppExcepInfo;
  425. ASSERT(pExcepInfo != NULL);
  426. Size = ExpandEnvironmentStringsW(ExceptionPackDir, InfName, MAX_PATH);
  427. InfName[MAX_PATH - 1] = 0;
  428. ASSERT(Size != 0 && Size < MAX_PATH);
  429. --Size;
  430. Size += (DWORD) StringFromGUID2(&pExcepInfo->guid, InfName + Size, MAX_PATH - Size);
  431. ASSERT(Size < MAX_PATH);
  432. InfName[Size - 1] = L'\\';
  433. wcsncpy(InfName + Size, pExcepInfo->InfName, MAX_PATH - Size);
  434. InfName[MAX_PATH - 1] = 0;
  435. }
  436. else if(NULL == RegVal->InfName.Buffer)
  437. {
  438. *InfName = 0;
  439. }
  440. else
  441. {
  442. wcsncpy(InfName, RegVal->InfName.Buffer, MAX_PATH - 1);
  443. InfName[MAX_PATH - 1] = 0;
  444. }
  445. RtlLeaveCriticalSection(&g_GeneralCS);
  446. return bException;
  447. }