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.

625 lines
20 KiB

  1. ;/*
  2. ; * Microsoft Confidential
  3. ; * Copyright (C) Microsoft Corporation 1991
  4. ; * All Rights Reserved.
  5. ; */
  6. /***************************************************************************/
  7. /* SETVER.C */
  8. /* */
  9. /* This module contains the functions which read in the version table */
  10. /* from MSDOS.SYS and then updates the table with new entries and */
  11. /* writes it back to the file. */
  12. /* */
  13. /* The fake version table is located in the DOS system file and it's */
  14. /* location and length are specified with 2 words at offset 7 in the */
  15. /* file. The first word is the table offset and second word is length. */
  16. /* */
  17. /* Table layout: */
  18. /* */
  19. /* ENTRY FILENAME LEN: Length of filename in bytes 1 byte */
  20. /* ENTRY FILENAME: Variable length to 12 bytes ? bytes */
  21. /* ENTRY VERSION MAJOR: Dos major version to return 1 byte */
  22. /* ENTRY VERSION MINOR: Dos minor version to return 1 byte */
  23. /* */
  24. /* */
  25. /* USEAGE: */
  26. /* List table: SETVER [D:] */
  27. /* Add entry: SETVER [D:] name.ext X.XX */
  28. /* Delete entry: SETVER [D:] name.ext /DELETE */
  29. /* Delete entry quietly: SETVER [D:] name.ext /DELETE /QUIET */
  30. /* Display help SETVER /? */
  31. /* */
  32. /* WHERE: */
  33. /* D: is the drive containing MSDOS.SYS */
  34. /* name.ext is the executable file name */
  35. /* X.XX is the major and minor version numbers */
  36. /* */
  37. /* RETURN CODES: */
  38. /* 0 Successful completion */
  39. /* 1 Invalid switch */
  40. /* 2 Invalid file name */
  41. /* 3 Insuffient memory */
  42. /* 4 Invalid version number format */
  43. /* 5 Entry not found in the table */
  44. /* 6 MSDOS.SYS file not found */
  45. /* 7 Invalid MSDOS.SYS or IBMDOS.SYS file */
  46. /* 8 Invalid drive specifier */
  47. /* 9 Too many command line parameters */
  48. /* 10 DOS version was not specified */
  49. /* 11 Missing parameter */
  50. /* 12 Error reading MS-DOS system file */
  51. /* 13 Version table is corrupt */
  52. /* 14 Specifed file does not support a version table */
  53. /* 15 Insuffient space in version table for new entry */
  54. /* 16 Error writing MS-DOS system file */
  55. /* */
  56. /* johnhe 05-01-90 */
  57. /***************************************************************************/
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <ctype.h>
  61. #include <string.h>
  62. #include <dos.h>
  63. #include <io.h>
  64. #include <fcntl.h>
  65. #include <setver.h>
  66. #include <message.h>
  67. /***************************************************************************/
  68. static char *ReadBuffer;
  69. static char *LieBuffer; /* Buffer to read lietable into */
  70. static char *EndBuf; /* Ptr to end of the buffer */
  71. struct ExeHeader ExeHdr;
  72. struct DevHeader DevHdr;
  73. struct TableEntry Entry;
  74. static char *szSetVer = "SETVERXX";
  75. long FileOffset;
  76. /* static UINT TableLen; */
  77. /***************************************************************************/
  78. /* Program entry point. Parses the command line and if it's valid executes */
  79. /* the requested function and then returns the proper error code. Any */
  80. /* error codes returned by ParseCommand are negative so they must be */
  81. /* converted with a negate before being returned as valid error codes. */
  82. /* */
  83. /* int main( int argc, char *argv[] ) */
  84. /* */
  85. /* ARGUMENTS: argc - Count of command line arguments */
  86. /* argv - Array of ptrs to argument strings */
  87. /* RETURNS: int - Valid return code for batch processing */
  88. /* */
  89. /***************************************************************************/
  90. int main( int argc, char *argv[] )
  91. {
  92. register iFunc;
  93. char szError[ 80 ];
  94. iFunc = ParseCmd( argc, argv, &Entry );
  95. if ( iFunc >= 0 )
  96. iFunc = DoFunction( iFunc );
  97. if ( iFunc != S_OK )
  98. {
  99. iFunc = -(iFunc);
  100. #ifdef BILINGUAL
  101. if (IsDBCSCodePage())
  102. {
  103. strcpy( szError, ErrorMsg[ 0 ] );
  104. strcat( szError, ErrorMsg[ iFunc ] );
  105. }
  106. else
  107. {
  108. strcpy( szError, ErrorMsg2[ 0 ] );
  109. strcat( szError, ErrorMsg2[ iFunc ] );
  110. }
  111. #else
  112. strcpy( szError, ErrorMsg[ 0 ] );
  113. strcat( szError, ErrorMsg[ iFunc ] );
  114. #endif
  115. PutStr( szError );
  116. #ifdef BILINGUAL
  117. if (IsDBCSCodePage())
  118. PutStr( szMiniHelp );
  119. else
  120. PutStr( szMiniHelp2 );
  121. #else
  122. PutStr( szMiniHelp );
  123. #endif
  124. }
  125. return( iFunc );
  126. }
  127. /***************************************************************************/
  128. /* Calls the appropriate function to do whatever was specified by the */
  129. /* user. The lie table if first read in except in the case only the help */
  130. /* function was requested. To be sure duplicate table entries are not */
  131. /* created a call to DeleteEntry with the new program name will be done */
  132. /* before the new entry is created. */
  133. /* */
  134. /* int DoFunction( int iFunc ) */
  135. /* */
  136. /* ARGUMENTS: iFunct - The function to be performed */
  137. /* RETURNS: int - S_OK if no errors else an error code */
  138. /* */
  139. /***************************************************************************/
  140. int DoFunction( int iFunc )
  141. {
  142. register iStatus;
  143. if ( iFunc == DO_HELP )
  144. {
  145. #ifdef BILINGUAL
  146. if (IsDBCSCodePage())
  147. DisplayMsg( Help );
  148. else
  149. DisplayMsg( Help2 );
  150. #else
  151. DisplayMsg( Help );
  152. #endif
  153. return( S_OK );
  154. }
  155. if ( iFunc == DO_ADD_FILE )
  156. #ifdef BILINGUAL
  157. if (IsDBCSCodePage())
  158. DisplayMsg( Warn );
  159. else
  160. DisplayMsg( Warn2 );
  161. #else
  162. DisplayMsg( Warn ); /* Read in the lie table and */
  163. #endif
  164. /* then decide what to do */
  165. if ( (iStatus = ReadVersionTable()) == S_OK )
  166. {
  167. if ( iFunc == DO_LIST )
  168. iStatus = DisplayTable();
  169. else
  170. {
  171. if ( (iFunc == DO_DELETE || iFunc == DO_QUIET) &&
  172. (iStatus = MatchFile( LieBuffer, Entry.szFileName )) < S_OK )
  173. return( iStatus );
  174. /* Always a delete before add */
  175. if ( (iStatus = DeleteEntry()) == S_OK && iFunc == DO_ADD_FILE )
  176. iStatus = AddEntry();
  177. if ( iStatus == S_OK &&
  178. (iStatus = WriteVersionTable()) == S_OK &&
  179. !(iFunc == DO_QUIET) )
  180. {
  181. #ifdef BILINGUAL
  182. if (IsDBCSCodePage())
  183. PutStr( SuccessMsg );
  184. else
  185. PutStr( SuccessMsg_2 );
  186. if ( SetVerCheck() == TRUE ) /* M001 */
  187. {
  188. if (IsDBCSCodePage())
  189. PutStr( SuccessMsg2 );
  190. else
  191. PutStr( SuccessMsg2_2 );
  192. }
  193. #else
  194. PutStr( SuccessMsg );
  195. if ( SetVerCheck() == TRUE ) /* M001 */
  196. PutStr( SuccessMsg2 );
  197. #endif
  198. }
  199. }
  200. }
  201. /* M001 Install check to see if currently in device chain */
  202. if ( iStatus == S_OK && iFunc != DO_QUIET && SetVerCheck() == FALSE )
  203. #ifdef BILINGUAL
  204. {
  205. if (IsDBCSCodePage())
  206. DisplayMsg( szNoLoadMsg );
  207. else
  208. DisplayMsg( szNoLoadMsg2 );
  209. }
  210. #else
  211. DisplayMsg( szNoLoadMsg );
  212. #endif
  213. return( iStatus );
  214. }
  215. /***************************************************************************/
  216. /* Displays the help text for "/?" option, or the warning text. */
  217. /* */
  218. /* void DisplayHelp( tbl ) */
  219. /* */
  220. /* ARGUMENTS: char *tbl[] */
  221. /* RETURNS: void */
  222. /* */
  223. /***************************************************************************/
  224. void DisplayMsg( char *tbl[] )
  225. {
  226. register i;
  227. for ( i = 0; tbl[i] != NULL; i++ )
  228. PutStr( tbl[ i ] );
  229. }
  230. /***************************************************************************/
  231. /* Displays all entries in the version table which must have already been */
  232. /* read into the work buffer. The name and version number are created as */
  233. /* as ascii string in a tempory buffer and then printed as a single string */
  234. /* in the format: */
  235. /* */
  236. /* 1234567890123456789 */
  237. /* FILENAME.EXT X.XX */
  238. /* */
  239. /* int DisplayTable( void ) */
  240. /* */
  241. /* ARGUMENTS: void */
  242. /* RETURNS: int - S_CORRUPT_TABLE if table corrupt else S_OK */
  243. /* */
  244. /***************************************************************************/
  245. int DisplayTable( void )
  246. {
  247. char *BufPtr;
  248. char *szTmp;
  249. char *szVersion;
  250. char szEntry[ 50 ];
  251. BufPtr = LieBuffer;
  252. szVersion = szEntry + VERSION_COLUMN;
  253. PutStr( "" );
  254. while ( *BufPtr != 0 && BufPtr < EndBuf )
  255. {
  256. /* Chk for table corruption */
  257. if ( !IsValidEntry( BufPtr ) )
  258. return( S_CORRUPT_TABLE );
  259. /* Copy file name and pad with spaces */
  260. strncpy( szEntry, BufPtr+1, (unsigned)((int)*BufPtr) );
  261. for ( szTmp = szEntry + *BufPtr; szTmp < szVersion; szTmp++ )
  262. *szTmp = ' ';
  263. /* Point to version number */
  264. BufPtr += *BufPtr;
  265. BufPtr++;
  266. /* Now create ascii version */
  267. itoa( (int)*(BufPtr++), szVersion, DECIMAL );
  268. strcat( szVersion, (int)*BufPtr < 10 ? ".0" : "." );
  269. itoa( (int)*(BufPtr++), strchr( szVersion, EOL ), DECIMAL );
  270. PutStr( szEntry );
  271. }
  272. if ( BufPtr == LieBuffer )
  273. #ifdef BILINGUAL
  274. {
  275. if (IsDBCSCodePage())
  276. PutStr( szTableEmpty );
  277. else
  278. PutStr( szTableEmpty2 );
  279. }
  280. #else
  281. PutStr( szTableEmpty );
  282. #endif
  283. return( S_OK );
  284. }
  285. /***************************************************************************/
  286. /* Deletes all matching entries in the version table by moving all of the */
  287. /* entries following the matched entry down in the buffer to replace the */
  288. /* entry being deleted. After the entries are moved down the residuals */
  289. /* at the end of the table must be zeroed out. Before returning the entire */
  290. /* end of the table buffer after the valid entries is zeroed out to remove */
  291. /* any possible corruption. */
  292. /* */
  293. /* int DeleteEntry( void ) */
  294. /* */
  295. /* ARGUMENTS: NONE */
  296. /* RETURNS: int - S_CORRUPT_TABLE if errors found else S_OK */
  297. /* */
  298. /***************************************************************************/
  299. int DeleteEntry( void )
  300. {
  301. char *pchPtr;
  302. char *pchTmp;
  303. int iOffset;
  304. UINT uEntryLen;
  305. UINT uBlockLen;
  306. pchPtr = LieBuffer;
  307. while ( (iOffset = MatchFile( pchPtr, Entry.szFileName )) >= 0 )
  308. {
  309. pchPtr = LieBuffer + iOffset; /* Move block down */
  310. uEntryLen = (UINT)((int)*pchPtr) + 3;
  311. uBlockLen = (UINT)(EndBuf - pchPtr) + uEntryLen;
  312. memmove( pchPtr, pchPtr + uEntryLen, uBlockLen );
  313. pchTmp = pchPtr + uBlockLen; /* Clean end of blk */
  314. memset( pchTmp, 0, uEntryLen );
  315. }
  316. if ( iOffset == S_ENTRY_NOT_FOUND ) /* Clean end of table */
  317. {
  318. if ( (pchTmp = GetNextFree()) != NULL )
  319. memset( pchTmp, 0, DevHdr.TblLen - (unsigned)(pchTmp - LieBuffer) );
  320. return( S_OK );
  321. }
  322. else
  323. return( S_CORRUPT_TABLE );
  324. }
  325. /***************************************************************************/
  326. /* Adds a new entry to the end of any existing entries in the version */
  327. /* table. There must be suffient room in the table for the entry or the */
  328. /* call will fail with a S_NO_ROOM error returned. */
  329. /* */
  330. /* int AddEntry( void ) */
  331. /* */
  332. /* ARGUMENTS: NONE */
  333. /* RETURNS: int - S_OK if room for entry else S_NO_ROOM */
  334. /* */
  335. /***************************************************************************/
  336. int AddEntry( void )
  337. {
  338. register iLen;
  339. char *pchNext;
  340. iLen = (int)strlen( Entry.szFileName ) + 3;
  341. if ( (pchNext = GetNextFree()) != NULL && iLen <= EndBuf - pchNext )
  342. {
  343. *pchNext = (char)(iLen - 3);
  344. strcpy( pchNext + 1, Entry.szFileName );
  345. pchNext += (int)(*pchNext) + 1;
  346. *(pchNext++) = (char)Entry.MajorVer;
  347. *pchNext = (char)Entry.MinorVer;
  348. return( S_OK );
  349. }
  350. else
  351. return( S_NO_ROOM );
  352. }
  353. /***************************************************************************/
  354. /* Returns the offset of a specified name in the version table. The start */
  355. /* of the search is specified by the caller so that searches for duplicate */
  356. /* entries can be made without redundency. NOTE: file name entries in the */
  357. /* version table are not zero terminated strings so the comparision must */
  358. /* be conditioned by length and the search strings length must be checked */
  359. /* to avoid an error caused by a match of a shorter table entry name. */
  360. /* */
  361. /* int MatchFile( char *pchStart, char *szFile ) */
  362. /* */
  363. /* ARGUMENTS: pchStart - Ptr specifying search starting point */
  364. /* szFile - Ptr to file name to match */
  365. /* RETURNS: int - Offset of entry from start of version */
  366. /* buffer or -1 if not match or */
  367. /* S_CORRUPT_TABLE if error */
  368. /* */
  369. /***************************************************************************/
  370. int MatchFile( char *pchPtr, char *szFile )
  371. {
  372. for ( ; pchPtr < EndBuf && *pchPtr != 0; pchPtr += *pchPtr + 3 )
  373. {
  374. if ( !IsValidEntry( pchPtr ) ) /* Corruption check */
  375. return( S_CORRUPT_TABLE );
  376. else if ( strncmp( szFile, pchPtr + 1, (UINT)((int)*pchPtr) ) == S_OK &&
  377. *(szFile + *pchPtr) == EOL )
  378. return( pchPtr - LieBuffer ); /* Return ptr offset */
  379. }
  380. return( S_ENTRY_NOT_FOUND ); /* Return no match */
  381. }
  382. /***************************************************************************/
  383. /* Checks a version table entry to see if it a valid entry. The definition */
  384. /* of a valid entry is one which has a file length less than MAX_NAME_LEN */
  385. /* and the entire entry lies within the version table. */
  386. /* */
  387. /* int IsValidEntry( char *pchPtr ) */
  388. /* */
  389. /* ARGUMENTS: pchPtr - Ptr to version tbl entry in table buffer */
  390. /* RETURNS: int - TRUE if entry is valid else FALSE */
  391. /* */
  392. /***************************************************************************/
  393. int IsValidEntry( char *pchPtr )
  394. {
  395. if ( (int)*pchPtr < MAX_NAME_LEN && (pchPtr + (int)*pchPtr + 3) < EndBuf )
  396. return( TRUE );
  397. else
  398. return( FALSE );
  399. }
  400. /***************************************************************************/
  401. /* Returns a pointer to the next free entry in the version table. If there */
  402. /* are no free entries left in the buffer a NULL ptr will be returned. */
  403. /* Since DeleteEntry is always called before AddEntry there is no check */
  404. /* for table corruption since it will have already been done by the */
  405. /* DeleteEntry call. */
  406. /* */
  407. /* char *GetNextFree( void ) */
  408. /* */
  409. /* ARGUMENTS: NONE */
  410. /* RETURNS: char* - Ptr to next free entry or NULL if tbl full */
  411. /* */
  412. /* NOTE: This caller of this function must check to be sure any entry any */
  413. /* entry to be added at the ptr returned will fit in the remaining */
  414. /* buffer area because the remaining buffer size may be less than */
  415. /* MAX_ENTRY_SIZE. */
  416. /* */
  417. /***************************************************************************/
  418. char *GetNextFree( void )
  419. {
  420. char *pchPtr;
  421. for ( pchPtr = LieBuffer; *pchPtr != 0 && pchPtr < EndBuf;
  422. pchPtr += *pchPtr + 3 )
  423. ;
  424. return( pchPtr < EndBuf ? pchPtr : NULL );
  425. }
  426. /***************************************************************************/
  427. /* Opens the DOS system file and reads in the table offset and length */
  428. /* structure. Then allocates a buffer and reads in the table. */
  429. /* */
  430. /* int ReadVersionTable( void ) */
  431. /* */
  432. /* ARGUMENTS: NONE */
  433. /* RETURNS: int - OK if successful else error code */
  434. /* */
  435. /***************************************************************************/
  436. int ReadVersionTable( void )
  437. {
  438. register iStatus; /* Function's return value */
  439. int iFile; /* DOS file handle */
  440. unsigned uRead; /* Number of bytes read from file */
  441. /* Open the file and read in the max buffer len from stack seg */
  442. if ( _dos_open( Entry.Path, O_RDONLY, &iFile ) != S_OK )
  443. return( S_FILE_NOT_FOUND );
  444. if ( _dos_read( iFile, &ExeHdr, sizeof( ExeHdr ), &uRead ) == S_OK &&
  445. uRead == sizeof( ExeHdr ) )
  446. {
  447. FileOffset += (long)(ExeHdr.HeaderParas * 16);
  448. if ( SeekRead( iFile, &DevHdr, FileOffset, sizeof( DevHdr ) ) == S_OK )
  449. {
  450. if ( strncmp( DevHdr.Name, szSetVer, 8 ) == S_OK &&
  451. DevHdr.VersMajor == 1 )
  452. {
  453. FileOffset += DevHdr.TblOffset;
  454. if ( (LieBuffer = malloc( DevHdr.TblLen )) == NULL )
  455. iStatus = S_MEMORY_ERROR;
  456. else if ( SeekRead( iFile, LieBuffer, FileOffset,
  457. DevHdr.TblLen ) == S_OK )
  458. {
  459. iStatus = S_OK;
  460. EndBuf = LieBuffer + DevHdr.TblLen;
  461. }
  462. }
  463. else
  464. iStatus = S_INVALID_SIG;
  465. }
  466. else
  467. iStatus = S_FILE_READ_ERROR;
  468. }
  469. else
  470. iStatus = S_FILE_READ_ERROR;
  471. _dos_close( iFile );
  472. return( iStatus );
  473. }
  474. /***************************************************************************/
  475. /* Opens the DOS system file and writes the versin table back to the file. */
  476. /* */
  477. /* int WriteVersionTable( void ) */
  478. /* */
  479. /* ARGUMENTS: NONE */
  480. /* RETURNS: int - OK if successful else error code */
  481. /* */
  482. /***************************************************************************/
  483. int WriteVersionTable( void )
  484. {
  485. register iStatus; /* Function's return value */
  486. int iFile; /* DOS file handle */
  487. unsigned uWritten; /* Number of bytes written to file */
  488. struct find_t Info;
  489. if ( _dos_findfirst( Entry.Path, _A_HIDDEN|_A_SYSTEM, &Info ) == S_OK &&
  490. _dos_setfileattr( Entry.Path, _A_NORMAL ) == S_OK &&
  491. _dos_open( Entry.Path, O_RDWR, &iFile ) == S_OK )
  492. {
  493. if ( _dos_seek( iFile, FileOffset, SEEK_SET ) == FileOffset &&
  494. _dos_write(iFile, LieBuffer, DevHdr.TblLen, &uWritten ) == S_OK &&
  495. uWritten == DevHdr.TblLen )
  496. iStatus = S_OK;
  497. else
  498. iStatus = S_FILE_WRITE_ERROR;
  499. _dos_setftime( iFile, Info.wr_date, Info.wr_time );
  500. _dos_close( iFile );
  501. _dos_setfileattr( Entry.Path, (UINT)((int)(Info.attrib)) );
  502. }
  503. else
  504. iStatus = S_FILE_NOT_FOUND;
  505. return( iStatus );
  506. }
  507. /***************************************************************************/
  508. /* Seeks to the specified offset in a file and reads in the specified */
  509. /* number of bytes into the caller's buffer. */
  510. /* */
  511. /* unsigned SeekRead( int iFile, char *Buf, long lOffset, unsigned uBytes )*/
  512. /* */
  513. /* ARGUMENTS: iFile - Open DOS file handle */
  514. /* Buf - Ptr to read buffer */
  515. /* lOffset - Offset in file to start reading at */
  516. /* uBytes - Number of bytes to read */
  517. /* RETURNS: unsigned - S_OK if successfull else S_FILE_READ_ERROR */
  518. /* */
  519. /***************************************************************************/
  520. int SeekRead( int iFile, void *Buf, long lOffset, unsigned uBytes )
  521. {
  522. unsigned uRead;
  523. if ( _dos_seek( iFile, lOffset, SEEK_SET ) == lOffset &&
  524. _dos_read( iFile, Buf, uBytes, &uRead ) == S_OK &&
  525. uRead == uBytes )
  526. return( S_OK );
  527. else
  528. return( S_FILE_READ_ERROR );
  529. }
  530. #ifdef BILINGUAL
  531. int IsDBCSCodePage()
  532. {
  533. union REGS inregs,outregs;
  534. inregs.x.ax = 0x4f01;
  535. int86(0x2f,&inregs,&outregs);
  536. #ifdef JAPAN
  537. if (outregs.x.bx == 932)
  538. #endif
  539. #ifdef KOREA
  540. if (outregs.x.bx == 949)
  541. #endif
  542. #ifdef PRC
  543. if (outregs.x.bx == 936)
  544. #endif
  545. #ifdef TAIWAN
  546. if (outregs.x.bx == 950)
  547. #endif
  548. return(1);
  549. else
  550. return(0);
  551. }
  552. #endif