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.

554 lines
14 KiB

  1. //-----------------------------------------------------------------------------
  2. #include "stdafx.h"
  3. #include "uddimsifiler.h"
  4. static PTCHAR GetFileLongName( PTCHAR szFileName );
  5. static PTCHAR GetErrorMsg( UINT iRet );
  6. static bool UpdateFileTable( void );
  7. static bool FileExists( PTCHAR szFileName );
  8. static bool UpdateFile( PTCHAR szFile, PTCHAR szFilePath );
  9. static bool LookupComponentTargetFolder( PTCHAR szComponent, PTCHAR szComponentFolder );
  10. static bool UpdateFileHash( PTCHAR szFile, PTCHAR szFilePath );
  11. static bool UpdateMSIVerFromFile( LPCTSTR szFile );
  12. static void LogError( LPCTSTR fmt, ... );
  13. PMSIHANDLE g_hDatabase;
  14. TCHAR g_MSIFile[ MAX_PATH + 1 ];
  15. TCHAR g_LogFile[ MAX_PATH + 1 ];
  16. TCHAR g_SourceDir[ MAX_PATH + 1 ];
  17. TCHAR g_VerFile[ MAX_PATH + 1 ];
  18. //--------------------------------------------------------------
  19. int __cdecl _tmain( int argc, TCHAR* argv[], TCHAR* envp[] )
  20. {
  21. UINT iRet = 0;
  22. bool bDisplayUsage = false;
  23. ZeroMemory( g_MSIFile, sizeof g_MSIFile );
  24. ZeroMemory( g_LogFile, sizeof g_LogFile );
  25. ZeroMemory( g_VerFile, sizeof g_VerFile );
  26. ZeroMemory( g_SourceDir, sizeof g_SourceDir );
  27. if ( argc > 1 )
  28. {
  29. // loop through all the arguments
  30. for ( int i=1; i<argc; i++ )
  31. {
  32. // -d is the path to the msi file
  33. if ( _tcscmp( argv[ i ], TEXT( "-d" ) )==0 )
  34. {
  35. i++;
  36. if ( i >= argc )
  37. {
  38. bDisplayUsage = true;
  39. break;
  40. }
  41. _tcscpy( g_MSIFile, argv[ i ] );
  42. continue;
  43. }
  44. // -s is the path to the source files
  45. if( 0 == _tcscmp( argv[ i ], TEXT( "-s" ) ) )
  46. {
  47. i++;
  48. if ( i >= argc )
  49. {
  50. bDisplayUsage = true;
  51. break;
  52. }
  53. _tcscpy( g_SourceDir, argv[ i ] );
  54. continue;
  55. }
  56. // -L is the log file
  57. if( 0 == _tcsicmp( argv[ i ], TEXT( "-L" ) ) )
  58. {
  59. i++;
  60. if ( i >= argc )
  61. {
  62. bDisplayUsage = true;
  63. break;
  64. }
  65. _tcscpy( g_LogFile, argv[ i ] );
  66. continue;
  67. }
  68. // -v is a file containing the version stamp
  69. if( 0 == _tcsicmp( argv[ i ], TEXT( "-v" ) ) )
  70. {
  71. i++;
  72. if ( i >= argc )
  73. {
  74. bDisplayUsage = true;
  75. break;
  76. }
  77. _tcscpy( g_VerFile, argv[ i ] );
  78. continue;
  79. }
  80. }
  81. }
  82. // usage
  83. if ( bDisplayUsage || argc == 1 || NULL != _tcsrchr( argv[ 1 ], '?' ) )
  84. {
  85. _tprintf( TEXT( "Updates the File Table with files in a folder ( using File.File key names )\n\n" ) );
  86. _tprintf( TEXT( "Usage: %s -d <MSI database> -s <location of files> [ -L <log file> ] [-v <product version file>]\n\n" ), argv[ 0 ] );
  87. return 0;
  88. }
  89. //
  90. // open the database
  91. //
  92. if( !FileExists( g_MSIFile ) )
  93. {
  94. LogError( TEXT( "***ERROR: MSI File does not exist: %s" ), g_MSIFile );
  95. return 1;
  96. }
  97. //
  98. // open the MSI file
  99. //
  100. iRet = MsiOpenDatabase( g_MSIFile, MSIDBOPEN_TRANSACT, &g_hDatabase );
  101. if( ERROR_SUCCESS != iRet )
  102. {
  103. LogError( TEXT( "***ERROR: MsiOpenDatabase Error: %s" ), GetErrorMsg( iRet ) );
  104. return 1;
  105. }
  106. bool bRet = UpdateFileTable();
  107. //
  108. // update the ProductVersion property
  109. //
  110. UpdateMSIVerFromFile( g_VerFile );
  111. iRet = MsiDatabaseCommit( g_hDatabase );
  112. if( ERROR_SUCCESS != iRet )
  113. {
  114. LogError( TEXT( "***ERROR: MsiDatabaseCommit Error: %s" ), GetErrorMsg( iRet ) );
  115. return 0;
  116. }
  117. return bRet ? 0 : 1;
  118. }
  119. //--------------------------------------------------------------
  120. static bool UpdateFileTable( void )
  121. {
  122. UINT iRet;
  123. PMSIHANDLE hView;
  124. PMSIHANDLE hRecord = 0;
  125. //
  126. // open a view and submit the SQL query
  127. //
  128. iRet = MsiDatabaseOpenView( g_hDatabase, TEXT( "select File from File" ), &hView );
  129. if( ERROR_SUCCESS != iRet )
  130. {
  131. LogError( TEXT( "***ERROR: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  132. return false;
  133. }
  134. //
  135. // execute the SQL query
  136. //
  137. iRet = MsiViewExecute( hView, hRecord );
  138. if( ERROR_SUCCESS != iRet )
  139. {
  140. LogError( TEXT( "***ERROR: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  141. return false;
  142. }
  143. //
  144. // fetch the data
  145. //
  146. TCHAR szFile[ 256 ];
  147. TCHAR szFilePath[ 256 ];
  148. DWORD cchValueBuf;
  149. while( ERROR_NO_MORE_ITEMS != MsiViewFetch( hView, &hRecord ) )
  150. {
  151. cchValueBuf = 256;
  152. MsiRecordGetString( hRecord, 1, szFile, &cchValueBuf );
  153. //
  154. // create the full path to the file in \binaries folder
  155. //
  156. _stprintf( szFilePath, TEXT( "%s\\%s" ), g_SourceDir, szFile );
  157. //LogError( TEXT( "Updating: %s\n" ), szFilePath );
  158. //
  159. // does the file exist?
  160. //
  161. if( !FileExists( szFilePath ) )
  162. {
  163. LogError( TEXT( "***ERROR: Source File does not exist: %s" ), szFilePath );
  164. return false;
  165. }
  166. //
  167. // update the size, version, language and hash table
  168. //
  169. if( !UpdateFile( szFile, szFilePath ) )
  170. {
  171. LogError( TEXT( "***ERROR: Unable to update file %s\n" ), szFile );
  172. return false;
  173. }
  174. }
  175. return true;
  176. }
  177. //--------------------------------------------------------------
  178. static bool UpdateFile( PTCHAR szFile, PTCHAR szFilePath )
  179. {
  180. PMSIHANDLE hView;
  181. PMSIHANDLE hRecord = 0;
  182. //
  183. // get the version and language of this file
  184. //
  185. TCHAR szVersionBuf[ 100 ];
  186. DWORD dwVersionBuf = 100;
  187. TCHAR szLanguageBuf[ 100 ];
  188. DWORD dwLanguageBuf = 100;
  189. UINT iRet = MsiGetFileVersion(
  190. szFilePath, // path to the file
  191. szVersionBuf, // returned version string
  192. &dwVersionBuf, // buffer byte count
  193. szLanguageBuf, // returned language string
  194. &dwLanguageBuf ); // buffer byte count
  195. if ( ERROR_SUCCESS != iRet )
  196. {
  197. _tcscpy( szVersionBuf, TEXT( "" ) );
  198. _tcscpy( szLanguageBuf, TEXT( "" ) );
  199. UpdateFileHash( szFile, szFilePath );
  200. }
  201. //
  202. // get the file's size
  203. //
  204. HANDLE hFile = CreateFile( szFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  205. if( INVALID_HANDLE_VALUE == hFile )
  206. {
  207. return false;
  208. }
  209. LARGE_INTEGER liSize;
  210. if( 0 == GetFileSizeEx( hFile, &liSize ) )
  211. {
  212. LogError( TEXT( "***ERROR: Unable to get file size for file %s\n" ), szFilePath );
  213. CloseHandle( hFile );
  214. return false;
  215. }
  216. CloseHandle( hFile );
  217. //
  218. // update the file's version, language and size
  219. //
  220. TCHAR szSQLQuery[ 256 ];
  221. _stprintf( szSQLQuery, TEXT( "UPDATE File SET FileSize = ?, Version = ?, Language = ? where File = ?" ) );
  222. iRet = MsiDatabaseOpenView( g_hDatabase, szSQLQuery, &hView );
  223. if ( ERROR_SUCCESS != iRet )
  224. {
  225. LogError( 0, TEXT( "***ERROR: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  226. return false;
  227. }
  228. // create a temp record to store the replacable values
  229. hRecord = MsiCreateRecord( 4 );
  230. if ( NULL == hRecord )
  231. {
  232. LogError( 0, TEXT( "***ERROR: MsiCreateRecord failed" ) );
  233. return false;
  234. }
  235. int index = 1;
  236. // Size goes in #1
  237. iRet = MsiRecordSetInteger( hRecord, index++, liSize.LowPart );
  238. if ( ERROR_SUCCESS != iRet )
  239. {
  240. LogError( 0, TEXT( "***ERROR: MsiRecordSetString Error: %s" ), GetErrorMsg( iRet ) );
  241. return false;
  242. }
  243. // Version goes in #2
  244. iRet = MsiRecordSetString( hRecord, index++, szVersionBuf );
  245. if ( ERROR_SUCCESS != iRet )
  246. {
  247. LogError( 0, TEXT( "***ERROR: MsiRecordSetString Error: %s" ), GetErrorMsg( iRet ) );
  248. return false;
  249. }
  250. // Language goes in #3
  251. iRet = MsiRecordSetString( hRecord, index++, szLanguageBuf );
  252. if ( ERROR_SUCCESS != iRet )
  253. {
  254. LogError( 0, TEXT( "***ERROR: MsiRecordSetString Error: %s" ), GetErrorMsg( iRet ) );
  255. return false;
  256. }
  257. // File goes in #4
  258. iRet = MsiRecordSetString( hRecord, index++, szFile );
  259. if ( ERROR_SUCCESS != iRet )
  260. {
  261. LogError( 0, TEXT( "***ERROR: MsiRecordSetString Error: %s" ), GetErrorMsg( iRet ) );
  262. return false;
  263. }
  264. // execute the update query
  265. iRet = MsiViewExecute( hView, hRecord );
  266. if ( ERROR_SUCCESS != iRet )
  267. {
  268. LogError( 0, TEXT( "***ERROR: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  269. return false;
  270. }
  271. return true;
  272. }
  273. //--------------------------------------------------------------
  274. static bool UpdateMSIVerFromFile( LPCTSTR szFileName )
  275. {
  276. MSIHANDLE hView;
  277. TCHAR szVersionBuf[ 256 ];
  278. TCHAR szLanguageBuf[ 256 ];
  279. TCHAR szQuery[ 256 ];
  280. DWORD dwLanguageBuf = 0, dwVersionBuf = 0;
  281. if ( !szFileName )
  282. return false;
  283. if ( !FileExists( (LPTSTR)szFileName ) )
  284. return false;
  285. dwVersionBuf = sizeof szVersionBuf / sizeof szVersionBuf[0];
  286. dwLanguageBuf = sizeof szLanguageBuf / sizeof szLanguageBuf[0];
  287. UINT iRet = MsiGetFileVersion( szFileName, // path to the file
  288. szVersionBuf, // returned version string
  289. &dwVersionBuf, // buffer byte count
  290. szLanguageBuf, // returned language string
  291. &dwLanguageBuf ); // buffer byte count
  292. if ( iRet != ERROR_SUCCESS )
  293. {
  294. LogError( TEXT( "***ERROR: MsiGetFileVersion Error: %s" ), GetErrorMsg( iRet ) );
  295. return false;
  296. }
  297. _tcscpy( szQuery, TEXT( "UPDATE Property SET Property.Value='" ) );
  298. _tcscat( szQuery, szVersionBuf );
  299. _tcscat( szQuery, TEXT("' WHERE Property.Property='ProductVersion'") );
  300. iRet = MsiDatabaseOpenView( g_hDatabase, szQuery, &hView );
  301. if ( ERROR_SUCCESS != iRet )
  302. {
  303. LogError( TEXT( "***ERROR: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  304. return false;
  305. }
  306. // execute the update query
  307. iRet = MsiViewExecute( hView, NULL );
  308. if ( ERROR_SUCCESS != iRet )
  309. {
  310. LogError( TEXT( "***ERROR: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  311. MsiCloseHandle( hView );
  312. return false;
  313. }
  314. MsiCloseHandle( hView );
  315. return true;
  316. }
  317. //--------------------------------------------------------------
  318. static bool UpdateFileHash( PTCHAR szFile, PTCHAR szFilePath )
  319. {
  320. PMSIHANDLE hView;
  321. PMSIHANDLE hRecord = 0;
  322. //
  323. // get the file's size
  324. //
  325. MSIFILEHASHINFO hashinfo;
  326. hashinfo.dwFileHashInfoSize = sizeof( MSIFILEHASHINFO );
  327. UINT iRet = MsiGetFileHash( szFilePath, 0, &hashinfo );
  328. if ( ERROR_SUCCESS != iRet )
  329. {
  330. LogError( 0, TEXT( "***ERROR: MsiGetFileHash Error: %s" ), GetErrorMsg( iRet ) );
  331. return false;
  332. }
  333. //
  334. // update the file's version, language and size
  335. //
  336. TCHAR szSQLQuery[ 256 ];
  337. _stprintf( szSQLQuery, TEXT( "UPDATE MsiFileHash SET HashPart1 = ?, HashPart2 = ?, HashPart3 = ?, HashPart4 = ? where File_ = ?" ) );
  338. iRet = MsiDatabaseOpenView( g_hDatabase, szSQLQuery, &hView );
  339. if ( ERROR_SUCCESS != iRet )
  340. {
  341. LogError( 0, TEXT( "***ERROR: MsiDatabaseOpenView Error: %s" ), GetErrorMsg( iRet ) );
  342. return false;
  343. }
  344. // create a temp record to store the replacable values
  345. hRecord = MsiCreateRecord( 5 );
  346. if ( NULL == hRecord )
  347. {
  348. LogError( 0, TEXT( "***ERROR: MsiCreateRecord failed" ) );
  349. return false;
  350. }
  351. int index = 1;
  352. for( int i=0; i<4; i++ )
  353. {
  354. iRet = MsiRecordSetInteger( hRecord, index++, hashinfo.dwData[ i ] );
  355. if ( ERROR_SUCCESS != iRet )
  356. {
  357. LogError( 0, TEXT( "***ERROR: MsiRecordSetInteger Error: %s" ), GetErrorMsg( iRet ) );
  358. return false;
  359. }
  360. }
  361. // File goes in #5
  362. iRet = MsiRecordSetString( hRecord, index++, szFile );
  363. if ( ERROR_SUCCESS != iRet )
  364. {
  365. LogError( 0, TEXT( "***ERROR: MsiRecordSetString Error: %s" ), GetErrorMsg( iRet ) );
  366. return false;
  367. }
  368. // execute the update query
  369. iRet = MsiViewExecute( hView, hRecord );
  370. if ( ERROR_SUCCESS != iRet )
  371. {
  372. LogError( 0, TEXT( "***ERROR: MsiViewExecute Error: %s" ), GetErrorMsg( iRet ) );
  373. return false;
  374. }
  375. return true;
  376. }
  377. //--------------------------------------------------------------
  378. static bool FileExists( PTCHAR szFileName )
  379. {
  380. FILE *file = _tfopen( szFileName, TEXT( "rt" ) );
  381. if( NULL == file )
  382. {
  383. return false;
  384. }
  385. fclose( file );
  386. return true;
  387. }
  388. //--------------------------------------------------------------
  389. static PTCHAR GetErrorMsg( UINT iRet )
  390. {
  391. static TCHAR szErrMsg[ 100 ];
  392. FormatMessage(
  393. FORMAT_MESSAGE_FROM_SYSTEM |
  394. FORMAT_MESSAGE_IGNORE_INSERTS,
  395. NULL,
  396. iRet,
  397. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  398. ( LPTSTR ) szErrMsg,
  399. 100,
  400. NULL );
  401. return szErrMsg;
  402. }
  403. //--------------------------------------------------------------------------
  404. static void LogError( LPCTSTR fmt, ... )
  405. {
  406. TCHAR szTime[ 10 ];
  407. TCHAR szDate[ 10 ];
  408. ::_tstrtime( szTime );
  409. ::_tstrdate( szDate );
  410. va_list marker;
  411. TCHAR szBuf[ 1024 ];
  412. size_t cbSize = ( sizeof( szBuf ) / sizeof( TCHAR ) ) - 1; // one byte for null
  413. _sntprintf( szBuf, cbSize, TEXT( "%s %s: " ), szDate, szTime );
  414. szBuf[ 1023 ] = '\0';
  415. cbSize -= _tcslen( szBuf );
  416. va_start( marker, fmt );
  417. _vsntprintf( szBuf + _tcslen( szBuf ), cbSize, fmt, marker );
  418. szBuf[ 1023 ] = '\0';
  419. cbSize -= _tcslen( szBuf );
  420. va_end( marker );
  421. _tcsncat( szBuf, TEXT( "\r\n" ), cbSize );
  422. _tprintf( TEXT( "%s" ), szBuf );
  423. if( 0 == _tcslen( g_LogFile ) )
  424. return;
  425. // write the data out to the log file
  426. char szBufA[ 1024 ];
  427. WideCharToMultiByte( CP_ACP, 0, szBuf, -1, szBufA, 1024, NULL, NULL );
  428. HANDLE hFile = CreateFile(
  429. g_LogFile, // file name
  430. GENERIC_WRITE, // open for writing
  431. 0, // do not share
  432. NULL, // no security
  433. OPEN_ALWAYS, // open and create if not exists
  434. FILE_ATTRIBUTE_NORMAL, // normal file
  435. NULL ); // no attr. template
  436. if( hFile == INVALID_HANDLE_VALUE )
  437. {
  438. return;
  439. }
  440. //
  441. // move the file pointer to the end so that we can append
  442. //
  443. SetFilePointer( hFile, 0, NULL, FILE_END );
  444. DWORD dwNumberOfBytesWritten;
  445. BOOL bOK = WriteFile(
  446. hFile,
  447. szBufA,
  448. ( UINT ) strlen( szBufA ), // number of bytes to write
  449. &dwNumberOfBytesWritten, // number of bytes written
  450. NULL ); // overlapped buffer
  451. FlushFileBuffers ( hFile );
  452. CloseHandle( hFile );
  453. }