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.

889 lines
26 KiB

  1. /*****************************************************************************\
  2. * MODULE: gencab.c
  3. *
  4. * The module contains routines for generating a self-extracting CAB file
  5. * for the IExpress utility. This relies on the cdfCreate and infCreate
  6. * to create the objects for the IExpress process.
  7. *
  8. *
  9. * Copyright (C) 1996-1997 Microsoft Corporation
  10. * Copyright (C) 1996-1997 Hewlett Packard
  11. *
  12. * History:
  13. * 22-Nov-1996 <chriswil> Created.
  14. *
  15. \*****************************************************************************/
  16. #include "pch.h"
  17. #include "spool.h"
  18. #include <initguid.h> // To define the IIS Metabase GUIDs used in this file. Every other file defines GUIDs as extern, except here where we actually define them in initguid.h.
  19. #include <iadmw.h> // Interface header
  20. #include <iiscnfg.h> // MD_ & IIS_MD_ defines
  21. #define CAB_TIMEOUT 1000
  22. /*****************************************************************************\
  23. * Critical Section Handling
  24. *
  25. \*****************************************************************************/
  26. DWORD gdwCritOwner = 0;
  27. VOID cab_enter_crit(VOID)
  28. {
  29. EnterCriticalSection(&g_csGenCab);
  30. gdwCritOwner = GetCurrentThreadId();
  31. }
  32. VOID cab_leave_crit(VOID)
  33. {
  34. gdwCritOwner = 0;
  35. LeaveCriticalSection(&g_csGenCab);
  36. }
  37. VOID cab_check_crit(VOID)
  38. {
  39. DWORD dwCurrent = GetCurrentThreadId();
  40. SPLASSERT((dwCurrent == gdwCritOwner));
  41. }
  42. #define EnterCABCrit() cab_enter_crit()
  43. #define LeaveCABCrit() cab_leave_crit()
  44. #define CheckCABCrit() cab_check_crit()
  45. /*****************************************************************************\
  46. * cab_SetClientSecurity (Local Routine)
  47. *
  48. * This routine sets the thread security so that it has max-privileges.
  49. *
  50. \*****************************************************************************/
  51. HANDLE cab_SetClientSecurity(VOID)
  52. {
  53. HANDLE hToken;
  54. HANDLE hThread = GetCurrentThread();
  55. if (OpenThreadToken(hThread, TOKEN_IMPERSONATE, TRUE, &hToken)) {
  56. if (SetThreadToken(&hThread, NULL)) {
  57. return hToken;
  58. }
  59. CloseHandle(hToken);
  60. }
  61. return NULL;
  62. }
  63. /*****************************************************************************\
  64. * cab_ResetClientSecurity (Local Routine)
  65. *
  66. * This routine resets the client-security to the token passed in. This
  67. * is called in order to set the thread to the original security attributes.
  68. *
  69. \*****************************************************************************/
  70. BOOL cab_ResetClientSecurity(
  71. HANDLE hToken)
  72. {
  73. BOOL bRet;
  74. bRet = SetThreadToken(NULL, hToken);
  75. CloseHandle(hToken);
  76. return bRet;
  77. }
  78. /*****************************************************************************\
  79. * cab_iexpress_sync (Local Routine)
  80. *
  81. * This routine sychronizes the process and won't return until the process
  82. * is done generating the CAB executable.
  83. *
  84. \*****************************************************************************/
  85. BOOL cab_iexpress_sync(
  86. HANDLE hProcess)
  87. {
  88. DWORD dwObj;
  89. DWORD dwExitCode;
  90. while (TRUE) {
  91. dwObj = WaitForSingleObject(hProcess, INFINITE);
  92. // Look for the exit type.
  93. //
  94. switch (dwObj) {
  95. // The process handle triggered the wait. Let's get the
  96. // exit-code and return whether the success. Otherwise,
  97. // drop through and return the failure.
  98. //
  99. case WAIT_OBJECT_0:
  100. GetExitCodeProcess(hProcess, &dwExitCode);
  101. if (dwExitCode == 0)
  102. return TRUE;
  103. // Something failed in the call. We failed.
  104. //
  105. case WAIT_FAILED:
  106. return FALSE;
  107. }
  108. }
  109. }
  110. /*****************************************************************************\
  111. * cab_force_delete_file
  112. *
  113. * Reset a files attributes before deleting it. We copied them to the temp dir
  114. * so we can delete them no matter what.
  115. *
  116. \*****************************************************************************/
  117. VOID cab_force_delete_file(
  118. LPCTSTR lpszFileName)
  119. {
  120. SetFileAttributes( lpszFileName, FILE_ATTRIBUTE_NORMAL );
  121. DeleteFile( lpszFileName );
  122. }
  123. /*****************************************************************************\
  124. * cab_cleanup_files
  125. *
  126. * Cleanup any files left-over in our generation process. Particularly,
  127. * this will remove cab-files.
  128. *
  129. \*****************************************************************************/
  130. VOID cab_cleanup_files(
  131. LPCTSTR lpszDstPath)
  132. {
  133. TCHAR szAllExt[MIN_CAB_BUFFER];
  134. HANDLE hFind;
  135. DWORD idx;
  136. DWORD cItems;
  137. LPTSTR lpszCurDir;
  138. WIN32_FIND_DATA wfd;
  139. static LPCTSTR s_szFiles[] = {
  140. g_szDotInf,
  141. g_szDotBin,
  142. g_szDotCat
  143. };
  144. // Put us into the destination directory where we
  145. // want to cleanup the files.
  146. //
  147. if (lpszCurDir = genGetCurDir()) {
  148. SetCurrentDirectory(lpszDstPath);
  149. // Delete the temporary dat-file used in building
  150. // the cdf-file
  151. //
  152. cab_force_delete_file(g_szDatFile);
  153. // Delete certain extension files.
  154. //
  155. cItems = sizeof(s_szFiles) / sizeof(s_szFiles[0]);
  156. for (idx = 0; idx < cItems; idx++) {
  157. StringCchPrintf(szAllExt, COUNTOF(szAllExt), TEXT("*%s"), s_szFiles[idx]);
  158. hFind = FindFirstFile(szAllExt, &wfd);
  159. if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
  160. do {
  161. cab_force_delete_file(wfd.cFileName);
  162. } while (FindNextFile(hFind, &wfd));
  163. FindClose(hFind);
  164. }
  165. }
  166. SetCurrentDirectory(lpszCurDir);
  167. genGFree(lpszCurDir, genGSize(lpszCurDir));
  168. }
  169. return;
  170. }
  171. /*****************************************************************************\
  172. * cab_rename_cab
  173. *
  174. * Renames the .CAB to the dstname.
  175. *
  176. \*****************************************************************************/
  177. BOOL cab_rename_cab(
  178. LPCTSTR lpszDstName)
  179. {
  180. LPTSTR lpszSrc;
  181. LPTSTR lpszDst;
  182. BOOL bRet = FALSE;
  183. if (lpszSrc = genBuildFileName(NULL, lpszDstName, g_szDotCab)) {
  184. if (lpszDst = genBuildFileName(NULL, lpszDstName, g_szDotIpp)) {
  185. bRet = MoveFileEx(lpszSrc, lpszDst, MOVEFILE_REPLACE_EXISTING);
  186. genGFree(lpszDst, genGSize(lpszDst));
  187. }
  188. genGFree(lpszSrc, genGSize(lpszSrc));
  189. }
  190. return bRet;
  191. }
  192. /*****************************************************************************\
  193. * cab_iexpress_exec (Local Routine)
  194. *
  195. * This exec's the IExpress utility to generate the self-extracting CAB
  196. * file.
  197. *
  198. \*****************************************************************************/
  199. BOOL cab_iexpress_exec(
  200. LPCTSTR lpszCabDir,
  201. LPCTSTR lpszDstName,
  202. LPCTSTR lpszSedFile)
  203. {
  204. PROCESS_INFORMATION pi;
  205. STARTUPINFO sti;
  206. LPTSTR lpszCmd;
  207. DWORD cbSize;
  208. LPTSTR lpszOldDir;
  209. BOOL bSuccess = FALSE;
  210. TCHAR szWindowDir[MAX_PATH];
  211. DWORD dwWinDirLen = 0;
  212. if (dwWinDirLen = GetSystemWindowsDirectory (szWindowDir, MAX_PATH))
  213. {
  214. if (szWindowDir[dwWinDirLen - 1] == TEXT ('\\'))
  215. {
  216. szWindowDir[dwWinDirLen - 1] = 0;
  217. }
  218. // Calculate enough space to hold the command-line arguments.
  219. //
  220. cbSize = (dwWinDirLen + lstrlen(lpszSedFile) + lstrlen(g_szCabCmd) + 1) * sizeof(TCHAR);
  221. // Allocate the command-line for the create-process call.
  222. //
  223. if (lpszCmd = (LPTSTR)genGAlloc(cbSize)) {
  224. // Initialize startup-info fields.
  225. //
  226. memset(&sti, 0, sizeof(STARTUPINFO));
  227. sti.cb = sizeof(STARTUPINFO);
  228. // Build the command-line string that exec's IExpress.
  229. //
  230. if (SUCCEEDED(StringCbPrintf(lpszCmd, cbSize, g_szCabCmd, szWindowDir, lpszSedFile)))
  231. {
  232. // Change the directory to the cab/sed directory. It
  233. // appears that IExpress requires this to generate.
  234. //
  235. if (lpszOldDir = genGetCurDir()) {
  236. SetCurrentDirectory(lpszCabDir);
  237. // Exec the process.
  238. //
  239. if (EXEC_PROCESS(lpszCmd, &sti, &pi)) {
  240. CloseHandle(pi.hThread);
  241. // This will wait until the process if finished generating
  242. // the file. The return from this indicates whether the
  243. // generation succeeded or not.
  244. //
  245. if (cab_iexpress_sync(pi.hProcess))
  246. bSuccess = cab_rename_cab(lpszDstName);
  247. CloseHandle(pi.hProcess);
  248. }
  249. // Restore our current-directory and free up any strings.
  250. //
  251. SetCurrentDirectory(lpszOldDir);
  252. genGFree(lpszOldDir, genGSize(lpszOldDir));
  253. }
  254. }
  255. genGFree(lpszCmd, cbSize);
  256. }
  257. }
  258. return bSuccess;
  259. }
  260. /*****************************************************************************\
  261. * cab_get_modtime
  262. *
  263. * Returns the modified-time of the CAB file. This can be used to determine
  264. * whether this is out of date with other files.
  265. *
  266. \*****************************************************************************/
  267. BOOL cab_get_modtime(
  268. LPTSTR lpszOutPath,
  269. LPFILETIME lpft)
  270. {
  271. HANDLE hFile;
  272. BOOL bRet = FALSE;
  273. // Open the file for reading.
  274. //
  275. hFile = gen_OpenFileRead(lpszOutPath);
  276. // If the file exists and was opened, go get the time.
  277. //
  278. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  279. bRet = GetFileTime(hFile, NULL, NULL, lpft);
  280. CloseHandle(hFile);
  281. }
  282. return bRet;
  283. }
  284. /*****************************************************************************\
  285. * cab_get_drvname (Local Routine)
  286. *
  287. * This routine attempts to open the printer, and retrieve the printer
  288. * driver-name associated with the FriendlyName. This returns to pointers
  289. * to a driver and a share-name.
  290. *
  291. \*****************************************************************************/
  292. BOOL cab_get_drvname(
  293. LPCTSTR lpszFriendlyName,
  294. LPTSTR* lpszDrvName,
  295. LPTSTR* lpszShrName,
  296. DWORD idxPlt
  297. )
  298. {
  299. HANDLE hPrinter;
  300. LPPRINTER_INFO_2 lppi;
  301. DWORD cbBuf;
  302. DWORD cbNeed;
  303. BOOL bRet = FALSE;
  304. // Initialize the pointers for the fail-case.
  305. //
  306. *lpszShrName = NULL;
  307. *lpszDrvName = NULL;
  308. // Open the printer and use the handle to query the printer for
  309. // the driver-name.
  310. //
  311. if (OpenPrinter((LPTSTR)lpszFriendlyName, &hPrinter, NULL)) {
  312. // First let's see how big our buffer will need to
  313. // be in order to hold the PRINTER_INFO_2.
  314. //
  315. cbBuf = 0;
  316. GetPrinter(hPrinter, PRT_LEV_2, NULL, 0, &cbBuf);
  317. // Allocate storage for holding the print-info structure.
  318. //
  319. if (cbBuf && (lppi = (LPPRINTER_INFO_2)genGAlloc(cbBuf))) {
  320. if (GetPrinter(hPrinter, PRT_LEV_2, (LPBYTE)lppi, cbBuf, &cbNeed)) {
  321. //If this is a Win9X client make sure the driver name is correct
  322. if ( genIsWin9X(idxPlt) )
  323. {
  324. // Call get printer driver to get the actual driver name for Win9X
  325. DWORD rc, cbNeeded;
  326. GetPrinterDriver( hPrinter, (LPTSTR) genStrCliEnvironment(idxPlt), 3,
  327. NULL, 0, &cbNeeded);
  328. rc = GetLastError();
  329. if ( rc == ERROR_INSUFFICIENT_BUFFER )
  330. {
  331. LPBYTE pData;
  332. DWORD dwSize = cbNeeded;
  333. if ( pData = (LPBYTE) genGAlloc(cbNeeded) )
  334. {
  335. if ( GetPrinterDriver( hPrinter, (LPTSTR) genStrCliEnvironment(idxPlt), 3,
  336. pData, dwSize, &cbNeeded) )
  337. {
  338. PDRIVER_INFO_3 pDriver = (PDRIVER_INFO_3) pData;
  339. *lpszDrvName = genGAllocStr(pDriver->pName);
  340. }
  341. genGFree( pData, dwSize );
  342. }
  343. }
  344. else
  345. *lpszDrvName = genGAllocStr(lppi->pDriverName);
  346. }
  347. else
  348. *lpszDrvName = genGAllocStr(lppi->pDriverName);
  349. if ( *lpszDrvName ) {
  350. if (*lpszShrName = genGAllocStr(lppi->pShareName)) {
  351. bRet = TRUE;
  352. } else {
  353. genGFree(*lpszDrvName, genGSize(*lpszDrvName));
  354. *lpszDrvName = NULL;
  355. }
  356. }
  357. }
  358. genGFree(lppi, cbBuf);
  359. }
  360. ClosePrinter(hPrinter);
  361. }
  362. return bRet;
  363. }
  364. /*****************************************************************************\
  365. * cab_get_dstname
  366. *
  367. * Returns the then name of the destination-files. The name built
  368. * incorporates the platform/version so that it is not duplicated with
  369. * any other files.
  370. *
  371. * <Share ChkSum><Arch><Ver>.webpnp
  372. *
  373. * i.e. <share chksum>AXP2 - NT Alpha 4.0
  374. * <share chksum>A863 - NT x86 5.0
  375. * <share chksum>AXP3 - NT Alpha 5.0
  376. * <share chksum>W9X0 - Win9X
  377. *
  378. \*****************************************************************************/
  379. LPTSTR cab_get_dstname(
  380. DWORD idxPlt,
  381. DWORD idxVer,
  382. LPCTSTR lpszShr)
  383. {
  384. int cchBuf;
  385. LPCTSTR lpszPlt;
  386. LPTSTR lpszName = NULL;
  387. // Get the platform requested for the client.
  388. //
  389. if (lpszPlt = genStrCliCab(idxPlt)) {
  390. cchBuf = lstrlen(lpszPlt) + MIN_CAB_BUFFER;
  391. // Build the cabname according to platform and version.
  392. //
  393. if (lpszName = (LPTSTR)genGAlloc(cchBuf * sizeof(TCHAR))) {
  394. if (FAILED(StringCchPrintf(lpszName, cchBuf, g_szCabName, genChkSum(lpszShr), lpszPlt, idxVer)))
  395. {
  396. genGFree(lpszName, genGSize(lpszName));
  397. lpszName = NULL;
  398. }
  399. }
  400. }
  401. return lpszName;
  402. }
  403. /*****************************************************************************\
  404. * cab_get_name
  405. *
  406. * Returns the name of the returned-file.
  407. *
  408. \*****************************************************************************/
  409. VOID cab_get_name(
  410. LPCTSTR lpszDstName,
  411. LPCTSTR lpszShrName,
  412. LPTSTR lpszName)
  413. {
  414. //
  415. // the buffer is allocated in msw3prt.cxx with MAX_PATH characters
  416. //
  417. StringCchPrintfW(lpszName, MAX_PATH, TEXT("/printers/%s/%s%s"), g_szPrtCabs, lpszDstName, g_szDotIpp);
  418. return;
  419. }
  420. /*****************************************************************************\
  421. * cab_get_webdir
  422. *
  423. * Returns the virtual-root-directory where the cab-files are to be generated
  424. * and stored.
  425. *
  426. \*****************************************************************************/
  427. LPTSTR cab_get_webdir(VOID)
  428. {
  429. HRESULT hr; // com error status
  430. METADATA_HANDLE hMeta = NULL; // handle to metabase
  431. CComPtr<IMSAdminBase> pIMeta; // ATL smart ptr
  432. DWORD dwMDRequiredDataLen;
  433. METADATA_RECORD mr;
  434. LPTSTR lpszDir = NULL;
  435. TCHAR szBuf[MAX_CAB_BUFFER];
  436. // Create a instance of the metabase object
  437. hr=::CoCreateInstance(CLSID_MSAdminBase,
  438. NULL,
  439. CLSCTX_ALL,
  440. IID_IMSAdminBase,
  441. (void **)&pIMeta);
  442. if ( SUCCEEDED( hr ) )
  443. {
  444. // open key to ROOT on website #1 (default)
  445. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  446. g_szMetabasePath,
  447. METADATA_PERMISSION_READ,
  448. CAB_TIMEOUT,
  449. &hMeta);
  450. if ( SUCCEEDED( hr ) )
  451. {
  452. mr.dwMDIdentifier = MD_VR_PATH;
  453. mr.dwMDAttributes = 0;
  454. mr.dwMDUserType = IIS_MD_UT_FILE;
  455. mr.dwMDDataType = STRING_METADATA;
  456. mr.dwMDDataLen = sizeof(szBuf);
  457. mr.pbMDData = reinterpret_cast<unsigned char *>(szBuf);
  458. hr = pIMeta->GetData( hMeta, L"", &mr, &dwMDRequiredDataLen );
  459. pIMeta->CloseKey( hMeta );
  460. if ( SUCCEEDED( hr ) )
  461. {
  462. lpszDir = genBuildFileName(szBuf, g_szPrtCabs, NULL);
  463. }
  464. }
  465. }
  466. return lpszDir;
  467. }
  468. /*****************************************************************************\
  469. * cab_get_dstpath
  470. *
  471. * Returns a directory string where the cabinet files are to be generated.
  472. *
  473. \*****************************************************************************/
  474. LPTSTR cab_get_dstpath(VOID)
  475. {
  476. HANDLE hDir;
  477. LPTSTR lpszDir;
  478. // First, we need to find the virtual-directory-root the cab files
  479. // are located.
  480. //
  481. if (lpszDir = cab_get_webdir()) {
  482. // Make sure the directory exists, or we can create it.
  483. //
  484. hDir = gen_OpenDirectory(lpszDir);
  485. if (hDir && (hDir != INVALID_HANDLE_VALUE)) {
  486. CloseHandle(hDir);
  487. } else {
  488. if (CreateDirectory(lpszDir, NULL) == FALSE) {
  489. genGFree(lpszDir, genGSize(lpszDir));
  490. lpszDir = NULL;
  491. }
  492. }
  493. }
  494. return lpszDir;
  495. }
  496. /*****************************************************************************\
  497. * GenerateCAB
  498. *
  499. * Main entry-point for generating the CAB file.
  500. *
  501. * Parameters
  502. * ----------
  503. * lpszFriendlyName - Name of printer (shared-name).
  504. * lpszPortName - Name of output port.
  505. * dwCliInfo - Client platform/architecture/version information.
  506. * lpszOutName - This is returned to the caller specifying the output.
  507. *
  508. \*****************************************************************************/
  509. DWORD GenerateCAB(
  510. LPCTSTR lpszFriendlyName,
  511. LPCTSTR lpszPortName,
  512. DWORD dwCliInfo,
  513. LPTSTR lpszOutName,
  514. BOOL bSecure)
  515. {
  516. INFGENPARM infParm;
  517. HANDLE hToken;
  518. HANDLE hsed;
  519. HANDLE hinf;
  520. FILETIME ftSED;
  521. FILETIME ftCAB;
  522. DWORD idxVer;
  523. DWORD idxPlt;
  524. BOOL bSed;
  525. BOOL bCab;
  526. LPTSTR lpszFullName;
  527. LPTSTR lpszDrvName = NULL;
  528. LPTSTR lpszShrName = NULL;
  529. LPTSTR lpszDstName = NULL;
  530. LPTSTR lpszDstPath = NULL;
  531. LPTSTR lpszFrnName = NULL;
  532. LPCTSTR lpszSedFile;
  533. DWORD dwRet = HSE_STATUS_ERROR;
  534. DWORD dwFailure = ERROR_SUCCESS;
  535. // Initialize the security-token so that we will have
  536. // max-privileges during the file-creation.
  537. //
  538. if ((hToken = cab_SetClientSecurity()) == NULL) {
  539. DBGMSG(DBG_ERROR, ("GenerateCab : Access Denied"));
  540. goto RetCabDone;
  541. }
  542. // Get the platform and version of the client (map to an index
  543. // into tables). Validate the indexes to assure the information
  544. // is valid.
  545. //
  546. idxPlt = genIdxCliPlatform(dwCliInfo);
  547. idxVer = genIdxCliVersion(dwCliInfo);
  548. if ((idxPlt == IDX_UNKNOWN) || (idxVer == IDX_UNKNOWN)) {
  549. dwFailure = ERROR_BAD_ENVIRONMENT;
  550. DBGMSG(DBG_ERROR, ("GenerateCab : Unsupported client architecture/version"));
  551. goto RetCabDone;
  552. }
  553. // Get the directory where the cab-files will be placed.
  554. //
  555. if ((lpszDstPath = cab_get_dstpath()) == NULL)
  556. goto RetCabDone;
  557. // Build a cluster-capable friendly-name.
  558. //
  559. if ((lpszFrnName = genFrnName(lpszFriendlyName)) == NULL)
  560. goto RetCabDone;
  561. // Get the driver information about the friendly-name.
  562. //
  563. if (cab_get_drvname(lpszFrnName, &lpszDrvName, &lpszShrName, idxPlt) == FALSE)
  564. goto RetCabDone;
  565. // Get the destination-name.
  566. //
  567. if ((lpszDstName = cab_get_dstname(idxPlt, idxVer, lpszShrName)) == NULL)
  568. goto RetCabDone;
  569. // Fill in the inf-input-parameters. These values should be
  570. // validated at this point.
  571. //
  572. infParm.lpszFriendlyName = lpszFrnName;
  573. infParm.lpszShareName = lpszShrName;
  574. infParm.lpszPortName = lpszPortName;
  575. infParm.idxPlt = idxPlt;
  576. infParm.idxVer = idxVer;
  577. infParm.dwCliInfo = dwCliInfo;
  578. infParm.lpszDrvName = lpszDrvName;
  579. infParm.lpszDstName = lpszDstName;
  580. infParm.lpszDstPath = lpszDstPath;
  581. // Grab the critical-section while we deal with generating
  582. // the files for the driver-install.
  583. //
  584. EnterCABCrit();
  585. // Call to have the INF/CDF files generated. If
  586. // all goes well, then the SED file can be generated
  587. // using the INF as input.
  588. //
  589. if (hinf = infCreate(&infParm)) {
  590. // We created an INF object. Now process the INF
  591. if ( infProcess(hinf) ) {
  592. // Got good INF so now work on CDF
  593. if (hsed = cdfCreate(hinf, bSecure)) {
  594. // We created a CDF object. Now process the CDF
  595. if ( cdfProcess(hsed) ) {
  596. // Allocate a string representing the full-path-name of
  597. // the generated executable.
  598. //
  599. lpszFullName = genBuildFileName(lpszDstPath, lpszDstName, g_szDotIpp);
  600. if (lpszFullName) {
  601. // Get the name of the directive file that we'll be using
  602. // to lauch the iexpress-package with. Do not delete this
  603. // pointer as it is handled by the SED object.
  604. //
  605. if (lpszSedFile = cdfGetName(hsed)) {
  606. // Retrieve modified dates so that we can determine whether
  607. // to generate a new-CAB or return an existing one. If the
  608. // calls return FALSE, the we can assume a file doesn't
  609. // exist, so we'll generate an new one anyway.
  610. //
  611. bSed = cdfGetModTime(hsed, &ftSED);
  612. bCab = cab_get_modtime(lpszFullName, &ftCAB);
  613. // Get the name of the Cab-File that will be
  614. // generated (or returned). This is relative to the
  615. // wwwroot path and is in the form /share/printer.
  616. //
  617. cab_get_name(lpszDstName, lpszShrName, lpszOutName);
  618. // If the bCabMod is TRUE (meaning we have a CAB), and the
  619. // SED is not newer than the CAB, then we really only need
  620. // to return the existing CAB. Otherwise, some files
  621. // must have changed.
  622. //
  623. if ((bSed && bCab) && (CompareFileTime(&ftSED, &ftCAB) <= 0)) {
  624. goto RetCabName;
  625. } else {
  626. if (cab_iexpress_exec(lpszDstPath, lpszDstName, lpszSedFile)) {
  627. RetCabName:
  628. dwRet = HSE_STATUS_SUCCESS;
  629. }
  630. else
  631. dwFailure = ERROR_CANNOT_MAKE;
  632. }
  633. }
  634. else // If cdfGetName
  635. dwFailure = GetLastError();
  636. genGFree(lpszFullName, genGSize(lpszFullName));
  637. }
  638. else // If lpszFullName
  639. dwFailure = GetLastError();
  640. }
  641. else // If cdfProcess()
  642. dwFailure = cdfGetError(hsed); // Get saved error
  643. cdfCleanUpSourceFiles(hinf); // Even if cdfProcess fails it might have
  644. // partialy generated some temporary files
  645. cdfDestroy(hsed);
  646. }
  647. else // If cdfCreate
  648. dwFailure = GetLastError();
  649. }
  650. else // If infProcess()
  651. dwFailure = infGetError(hinf); // Get saved error
  652. infDestroy(hinf);
  653. }
  654. else // If infCreate
  655. dwFailure = GetLastError();
  656. // Cleanup the files generated during processing.
  657. //
  658. cab_cleanup_files(lpszDstPath);
  659. RetCabDone:
  660. // If something failed but we don't know what yet.. Get the error
  661. if ( (dwRet == HSE_STATUS_ERROR) && ( dwFailure == ERROR_SUCCESS ) )
  662. dwFailure = GetLastError();
  663. // Free our strings allocated through this scope.
  664. //
  665. if (lpszFrnName)
  666. genGFree(lpszFrnName, genGSize(lpszFrnName));
  667. if (lpszDrvName)
  668. genGFree(lpszDrvName, genGSize(lpszDrvName));
  669. if (lpszDstName)
  670. genGFree(lpszDstName, genGSize(lpszDstName));
  671. if (lpszShrName)
  672. genGFree(lpszShrName, genGSize(lpszShrName));
  673. if (lpszDstPath)
  674. genGFree(lpszDstPath, genGSize(lpszDstPath));
  675. if (hToken)
  676. cab_ResetClientSecurity(hToken);
  677. LeaveCABCrit();
  678. if (dwFailure != ERROR_SUCCESS)
  679. SetLastError(dwFailure);
  680. return dwRet;
  681. }