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.

477 lines
13 KiB

  1. //-----------------------------------------------------------------------------
  2. #include "stdafx.h"
  3. #include "msitoddf.h"
  4. static PTCHAR GetFileLongName( PTCHAR szFileName );
  5. static PTCHAR GetErrorMsg( UINT iRet );
  6. static bool CreateCABDDF( void );
  7. static bool FileExists( PTCHAR szFileName );
  8. static bool CreateCabsTableDefinitionFile( void );
  9. static bool LookupComponentTargetFolder( PTCHAR szComponent, PTCHAR szComponentFolder );
  10. static void Log( LPCTSTR fmt, ... );
  11. PMSIHANDLE g_hDatabase;
  12. PMSIHANDLE g_hInstall;
  13. UINT g_iFileCount;
  14. TCHAR g_MSIFile[ MAX_PATH ];
  15. TCHAR g_LogFile[ MAX_PATH ];
  16. TCHAR g_DDFFile[ MAX_PATH ];
  17. TCHAR g_CABFile[ MAX_PATH ];
  18. TCHAR g_RootDir[ MAX_PATH ];
  19. //--------------------------------------------------------------
  20. int __cdecl _tmain( int argc, TCHAR* argv[], TCHAR* envp[] )
  21. {
  22. UINT iRet = 0;
  23. if( argc < 2 )
  24. {
  25. _tprintf( TEXT( "Extracts the file list from an MSI installer database and creates a DDF file\n\n" ) );
  26. _tprintf( TEXT( "Usage: %s <MSI file path> [-L <error log file path>]\n\n" ), argv[ 0 ] );
  27. return 1;
  28. }
  29. //MessageBox( NULL, TEXT( "UDDI" ), TEXT( "UDDI" ), MB_OK) ;
  30. _tcscpy( g_MSIFile, argv[ 1 ] );
  31. TCHAR szDrive[ _MAX_DRIVE ];
  32. TCHAR szPath[ _MAX_DIR ];
  33. TCHAR szFileName[ _MAX_FNAME ];
  34. _tsplitpath( g_MSIFile, szDrive, szPath, szFileName, NULL );
  35. _stprintf( g_DDFFile, TEXT( "%s%s%s.DDF" ), szDrive, szPath, szFileName );
  36. _stprintf( g_CABFile, TEXT( "%s.CAB" ), szFileName );
  37. _stprintf( g_RootDir, TEXT( "%s%s" ), szDrive, szPath );
  38. if( argc > 3 && 0 == _tcsicmp( argv[ 2 ], TEXT( "-L" ) ) )
  39. {
  40. _tcsncpy( g_LogFile, argv[ 3 ], MAX_PATH );
  41. }
  42. else
  43. {
  44. *g_LogFile = NULL;
  45. }
  46. //
  47. // open the database
  48. //
  49. if( !FileExists( g_MSIFile ) )
  50. {
  51. Log( TEXT( "*** Error: MSI File does not exist: %s" ), g_MSIFile );
  52. return 1;
  53. }
  54. iRet = MsiOpenDatabase( g_MSIFile, MSIDBOPEN_READONLY, &g_hDatabase );
  55. if( ERROR_SUCCESS != iRet )
  56. {
  57. Log( TEXT( "*** Error: MsiOpenDatabase Error: %s" ), GetErrorMsg( iRet ) );
  58. return 1;
  59. }
  60. //
  61. // get a database handle
  62. //
  63. TCHAR szDBHandle[ 10 ];
  64. _stprintf( szDBHandle, TEXT( "#%d" ), (DWORD) (MSIHANDLE) g_hDatabase );
  65. iRet = MsiOpenPackage( szDBHandle, &g_hInstall );
  66. if( ERROR_SUCCESS != iRet )
  67. {
  68. Log( TEXT( "*** Error: MsiOpenPackage Error: %s" ), GetErrorMsg( iRet ) );
  69. }
  70. else
  71. {
  72. if( ERROR_SUCCESS != MsiDoAction( g_hInstall, TEXT( "CostInitialize" ) ) )
  73. return 1;
  74. if( ERROR_SUCCESS != MsiDoAction( g_hInstall, TEXT( "FileCost" ) ) )
  75. return 1;
  76. if( ERROR_SUCCESS != MsiDoAction( g_hInstall, TEXT( "CostFinalize" ) ) )
  77. return 1;
  78. if( !CreateCABDDF() )
  79. return 1;
  80. }
  81. //
  82. // commit the changes
  83. //
  84. iRet = MsiDatabaseCommit( g_hDatabase );
  85. if( ERROR_SUCCESS != iRet )
  86. {
  87. Log( TEXT( "*** Error: MsiDatabaseCommit Error: %s" ), GetErrorMsg( iRet ) );
  88. return 1;
  89. }
  90. return 0;
  91. }
  92. //--------------------------------------------------------------
  93. static bool CreateCABDDF( void )
  94. {
  95. UINT iRet;
  96. PMSIHANDLE hView;
  97. PMSIHANDLE hRecord = 0;
  98. //
  99. // the install dir will give us the root of the path that we
  100. // can use later and trim it off
  101. //
  102. TCHAR szInstallDir[ _MAX_PATH ];
  103. DWORD dwSize = _MAX_PATH;
  104. iRet = MsiGetProperty( g_hInstall, TEXT("uddi"), szInstallDir, &dwSize );
  105. if( ERROR_SUCCESS != iRet )
  106. {
  107. Log( TEXT( "*** Error: MsiGetProperty Error: %s" ), GetErrorMsg( iRet ) );
  108. return false;
  109. }
  110. //
  111. // open a view and submit the SQL query
  112. //
  113. TCHAR szSQLQuery[ 256 ];
  114. _stprintf( szSQLQuery, TEXT( "select File, FileName, Component_, Sequence from File order by Sequence" ) );
  115. iRet = MsiDatabaseOpenView( g_hDatabase, szSQLQuery , &hView );
  116. if( ERROR_SUCCESS != iRet )
  117. {
  118. Log( TEXT( "*** Error: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  119. return false;
  120. }
  121. //
  122. // execute the SQL query
  123. //
  124. iRet = MsiViewExecute( hView, hRecord );
  125. if( ERROR_SUCCESS != iRet )
  126. {
  127. Log( TEXT( "*** Error: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  128. return false;
  129. }
  130. //
  131. // open the DDF file
  132. //
  133. FILE *file = _tfopen( g_DDFFile, TEXT( "w" ) );
  134. if( NULL == file )
  135. {
  136. Log( TEXT( "*** Error: Unable to open output file: %s, Error code %d" ), g_DDFFile, GetLastError() );
  137. return false;
  138. }
  139. //
  140. // header in DDF file used by makecab.exe
  141. //
  142. _fputts( TEXT( ".Option Explicit\n" ), file );
  143. _fputts( TEXT( ".Set DiskDirectoryTemplate=.\n" ), file );
  144. _fputts( TEXT( ".Set CabinetName1=" ), file );
  145. _fputts( g_CABFile, file );
  146. _fputts( TEXT( "\n" ), file );
  147. _fputts( TEXT( ".Set RptFilename=nul\n" ), file );
  148. _fputts( TEXT( ".Set InfFileName=nul\n" ), file );
  149. _fputts( TEXT( ".Set InfAttr=\n" ), file );
  150. _fputts( TEXT( ".Set MaxDiskSize=CDROM\n" ), file );
  151. _fputts( TEXT( ".Set CompressionType=LZX\n" ), file );
  152. _fputts( TEXT( ".Set CompressionMemory=21\n" ), file );
  153. _fputts( TEXT( ".Set CompressionLevel=1\n" ), file );
  154. _fputts( TEXT( ".Set Compress=ON\n" ), file );
  155. _fputts( TEXT( ".Set Cabinet=ON\n" ), file );
  156. _fputts( TEXT( ".Set UniqueFiles=ON\n" ), file );
  157. _fputts( TEXT( ".Set FolderSizeThreshold=1000000\n" ), file );
  158. _fputts( TEXT( ".Set MaxErrors=300\n" ), file );
  159. //
  160. // fetch the data
  161. //
  162. TCHAR szFile[ 256 ];
  163. TCHAR szFileName[ 256 ];
  164. TCHAR szComponent[ 256 ];
  165. TCHAR szComponentFolder[ 256 ];
  166. TCHAR szFilePath[ 256 ];
  167. int iSequence;
  168. DWORD cchValueBuf;
  169. g_iFileCount = 0;
  170. while( ERROR_NO_MORE_ITEMS != MsiViewFetch( hView, &hRecord ) )
  171. {
  172. g_iFileCount++;
  173. cchValueBuf = 256;
  174. MsiRecordGetString( hRecord, 1, szFile, &cchValueBuf );
  175. cchValueBuf = 256;
  176. MsiRecordGetString( hRecord, 2, szFileName, &cchValueBuf );
  177. cchValueBuf = 256;
  178. MsiRecordGetString( hRecord, 3, szComponent, &cchValueBuf );
  179. iSequence = MsiRecordGetInteger( hRecord, 4 );
  180. //
  181. // query the MSI for the target folder for this file.
  182. // this will tell us where it is located in the \binaries folders.
  183. //
  184. if( !LookupComponentTargetFolder( szComponent, szComponentFolder ) )
  185. {
  186. Log( TEXT( "**ERROR: Unable to find directory for component: %s" ), szComponent );
  187. return false;
  188. }
  189. TCHAR szWindowsDir[ MAX_PATH ];
  190. if( 0 == ExpandEnvironmentStrings( TEXT( "%systemroot%" ), szWindowsDir, MAX_PATH ) )
  191. return false;
  192. //_tprintf( TEXT( "windir=%s\n" ), szWindowsDir );
  193. //_tprintf( TEXT( "szComponentFolder=%s\n" ), szComponentFolder );
  194. //
  195. // look for files that are in the windows folder
  196. //
  197. if( 0 == _tcsnicmp( szComponentFolder, szWindowsDir, _tcslen( szWindowsDir ) ) )
  198. {
  199. //
  200. // create the full path to the file in \binaries folder. e.g. \binaries\uddi\windows\system32
  201. //
  202. _stprintf( szFilePath, TEXT( "%s%s%s" ),
  203. g_RootDir, // start with the root (c:\binariesx\uddi\)
  204. szComponentFolder + _tcslen( szWindowsDir ) + 1,
  205. GetFileLongName( szFileName ) ); // add file name
  206. }
  207. else
  208. {
  209. //
  210. // create the full path to the file in \binaries folder
  211. //
  212. _stprintf( szFilePath, TEXT( "%s%s%s" ),
  213. g_RootDir, // start with the root (c:\binariesx\uddi)
  214. &szComponentFolder[ _tcslen( szInstallDir ) ], // strip installdir prefix and append
  215. GetFileLongName( szFileName ) ); // add file name
  216. }
  217. //
  218. // if it exists (and it should), trim the c:\binaries\... part on put the file
  219. // name into the DDF file
  220. //
  221. if( FileExists( szFilePath ) )
  222. {
  223. _fputts( TEXT( "\"" ), file );
  224. _fputts( &szFilePath[ _tcslen( g_RootDir ) ], file ); // trim the root dir
  225. _fputts( TEXT( "\"\t\"" ), file );
  226. _fputts( szFile, file );
  227. _fputts( TEXT( "\"\n" ), file );
  228. }
  229. else
  230. {
  231. fclose( file );
  232. Log( TEXT( "*** ERROR: Source File does not exist: %s" ), szFilePath );
  233. Log( TEXT( "File=%s, %s" ), szFile, szFileName );
  234. Log( TEXT( "Component=%s" ), szComponent );
  235. Log( TEXT( "Component Folder=%s" ), szComponentFolder );
  236. Log( TEXT( "systemroot=%s" ), szWindowsDir );
  237. return false;
  238. }
  239. }
  240. fclose( file );
  241. return true;
  242. }
  243. //--------------------------------------------------------------
  244. static bool LookupComponentTargetFolder( PTCHAR szComponent, PTCHAR szComponentFolder )
  245. {
  246. UINT iRet;
  247. PMSIHANDLE hView;
  248. PMSIHANDLE hRecord = 0;
  249. //
  250. // open a view and submit the SQL query
  251. //
  252. TCHAR szSQLQuery[ 256 ];
  253. _stprintf( szSQLQuery, TEXT( "select Directory_ from Component where Component = '%s'" ), szComponent );
  254. iRet = MsiDatabaseOpenView( g_hDatabase, szSQLQuery , &hView );
  255. if( ERROR_SUCCESS != iRet )
  256. {
  257. Log( TEXT( "*** Error: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  258. return false;
  259. }
  260. //
  261. // execute the SQL query
  262. //
  263. iRet = MsiViewExecute( hView, hRecord );
  264. if( ERROR_SUCCESS != iRet )
  265. {
  266. Log( TEXT( "*** Error: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  267. return false;
  268. }
  269. //
  270. // fetch the data
  271. //
  272. TCHAR szDirectoryKey[ 256 ];
  273. DWORD cchValueBuf = 256;
  274. if( ERROR_SUCCESS != MsiViewFetch( hView, &hRecord ) )
  275. {
  276. Log( TEXT( "*** ERROR: Directory not found for component [ %s ]" ), szComponent );
  277. return false;
  278. }
  279. // get the key into the Directory table
  280. MsiRecordGetString( hRecord, 1, szDirectoryKey, &cchValueBuf );
  281. // look up the full path
  282. DWORD cchPathBuf = 256;
  283. iRet = MsiGetTargetPath( g_hInstall, szDirectoryKey, szComponentFolder, &cchPathBuf );
  284. if( ERROR_SUCCESS != iRet )
  285. {
  286. Log( TEXT( "*** Error: MsiGetSourcePath Error component [ %s ] %s" ), szComponent, GetErrorMsg( iRet ) );
  287. return false;
  288. }
  289. return true;
  290. }
  291. //--------------------------------------------------------------
  292. // returns the long file name out of a string that has both
  293. // short and long name separated by a pipe character
  294. static PTCHAR GetFileLongName( PTCHAR szFileName )
  295. {
  296. PTCHAR pStart = _tcschr( szFileName, TEXT( '|' ) );
  297. if( pStart )
  298. {
  299. return pStart + 1; // add 1 to skip over the pipe symbol
  300. }
  301. return szFileName;
  302. }
  303. //--------------------------------------------------------------
  304. static bool FileExists( PTCHAR szFileName )
  305. {
  306. FILE *file = _tfopen( szFileName, TEXT( "rt" ) );
  307. if( NULL == file )
  308. {
  309. return false;
  310. }
  311. fclose( file );
  312. return true;
  313. }
  314. //--------------------------------------------------------------------------
  315. static bool SetProperty( PTCHAR szProperty, PTCHAR szValue )
  316. {
  317. UINT iRet = MsiSetProperty( g_hInstall, szProperty, szValue );
  318. if( ERROR_SUCCESS != iRet )
  319. {
  320. Log( TEXT( "*** Error: SetProperty Error: %s, Property %s, Value %s" ),
  321. GetErrorMsg( iRet ),
  322. szProperty,
  323. szValue );
  324. return false;
  325. }
  326. return true;
  327. }
  328. //--------------------------------------------------------------
  329. static PTCHAR GetErrorMsg( UINT iRet )
  330. {
  331. static TCHAR szErrMsg[ 100 ];
  332. FormatMessage(
  333. FORMAT_MESSAGE_FROM_SYSTEM |
  334. FORMAT_MESSAGE_IGNORE_INSERTS,
  335. NULL,
  336. iRet,
  337. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  338. ( LPTSTR ) szErrMsg,
  339. 100,
  340. NULL);
  341. return szErrMsg;
  342. }
  343. //--------------------------------------------------------------------------
  344. static void Log( LPCTSTR fmt, ... )
  345. {
  346. TCHAR szTime[ 10 ];
  347. TCHAR szDate[ 10 ];
  348. ::_tstrtime( szTime );
  349. ::_tstrdate( szDate );
  350. va_list marker;
  351. TCHAR szBuf[1024];
  352. size_t cbSize = ( sizeof( szBuf ) / sizeof( TCHAR ) ) - 1; // one byte for null
  353. _sntprintf( szBuf, cbSize, TEXT( "%s %s: " ), szDate, szTime );
  354. szBuf[ 1023 ] = '\0';
  355. cbSize -= _tcslen( szBuf );
  356. va_start( marker, fmt );
  357. _vsntprintf( szBuf + _tcslen( szBuf ), cbSize, fmt, marker );
  358. szBuf[ 1023 ] = '\0';
  359. cbSize -= _tcslen( szBuf );
  360. va_end( marker );
  361. _tcsncat(szBuf, TEXT("\r\n"), cbSize );
  362. _tprintf( TEXT( "%s" ), szBuf );
  363. if( 0 == _tcslen( g_LogFile ) )
  364. return;
  365. // write the data out to the log file
  366. char szBufA[ 1024 ];
  367. WideCharToMultiByte( CP_ACP, 0, szBuf, -1, szBufA, 1024, NULL, NULL );
  368. HANDLE hFile = CreateFile(
  369. g_LogFile, // file name
  370. GENERIC_WRITE, // open for writing
  371. 0, // do not share
  372. NULL, // no security
  373. OPEN_ALWAYS, // open and create if not exists
  374. FILE_ATTRIBUTE_NORMAL, // normal file
  375. NULL); // no attr. template
  376. if( hFile == INVALID_HANDLE_VALUE )
  377. {
  378. return;
  379. }
  380. //
  381. // move the file pointer to the end so that we can append
  382. //
  383. SetFilePointer( hFile, 0, NULL, FILE_END );
  384. DWORD dwNumberOfBytesWritten;
  385. BOOL bOK = WriteFile(
  386. hFile,
  387. szBufA,
  388. (UINT) strlen( szBufA ), // number of bytes to write
  389. &dwNumberOfBytesWritten, // number of bytes written
  390. NULL); // overlapped buffer
  391. FlushFileBuffers ( hFile );
  392. CloseHandle( hFile );
  393. }