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.

2237 lines
88 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <private.h>
  5. #include <crt\io.h>
  6. #include <share.h>
  7. #include <time.h>
  8. #include <setupapi.h>
  9. #include "splitsymx.h"
  10. #include <string.h>
  11. #include "wppfmt.h"
  12. #include <VerifyFinalImage.h>
  13. #include <GetNextArg.h>
  14. #include <strsafe.h>
  15. #ifndef MOVEFILE_CREATE_HARDLINK
  16. #define MOVEFILE_CREATE_HARDLINK 0x00000010
  17. #endif
  18. #define BINPLACE_ERR 77
  19. #define BINPLACE_OK 0
  20. // begin from PlaceFileMatch.c
  21. #define BINPLACE_FULL_MAX_PATH 4096 // keep in sync with value in PlaceFileMatch.c
  22. BOOL
  23. PlaceFileMatch(
  24. IN LPCSTR FullFileName,
  25. IN OUT LPSTR PlaceFileEntry, // May be modified by env. var expansion
  26. OUT LPSTR PlaceFileClass, // assumed CHAR[BINPLACE_MAX_FULL_PATH]
  27. OUT LPSTR *PlaceFileNewName);
  28. // end
  29. BOOL fUpDriver;
  30. BOOL fBypassSplitSymX;
  31. BOOL fUsage;
  32. BOOL fVerbose;
  33. BOOL fSymChecking;
  34. BOOL fTestMode;
  35. BOOL fSplitSymbols;
  36. BOOL fPatheticOS;
  37. BOOL fKeepAttributes;
  38. BOOL fDigitalSign;
  39. BOOL fHardLinks;
  40. BOOL fIgnoreHardLinks;
  41. BOOL fDontLog;
  42. BOOL fPlaceWin95SymFile;
  43. BOOL fNoClassInSymbolsDir;
  44. BOOL fMakeErrorOnDumpCopy;
  45. BOOL fDontExit;
  46. BOOL fForcePlace;
  47. BOOL fSignCode;
  48. BOOL fVerifyLc;
  49. BOOL fWppFmt;
  50. BOOL fCheckDelayload;
  51. BOOL fChangeAsmsToRetailForSymbols;
  52. BOOL fSrcControl;
  53. BOOL fDbgControl;
  54. BOOL fLogPdbPaths;
  55. HINSTANCE hSetupApi;
  56. HINSTANCE hLcManager;
  57. PVLCA pVerifyLocConstraintA; // PVLCA defined in VerifyFinalImage.h
  58. BOOL (WINAPI * pSetupGetIntField) (IN PINFCONTEXT Context, IN DWORD FieldIndex, OUT PINT IntegerValue);
  59. BOOL (WINAPI * pSetupFindFirstLineA) (IN HINF InfHandle, IN PCSTR Section, IN PCSTR Key, OPTIONAL OUT PINFCONTEXT Context );
  60. BOOL (WINAPI * pSetupGetStringFieldA) (IN PINFCONTEXT Context, IN DWORD FieldIndex, OUT PSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize);
  61. HINF (WINAPI * pSetupOpenInfFileA) ( IN PCSTR FileName, IN PCSTR InfClass, OPTIONAL IN DWORD InfStyle, OUT PUINT ErrorLine OPTIONAL );
  62. HINF (WINAPI * pSetupOpenMasterInf) (VOID);
  63. ULONG SplitFlags = 0;
  64. LPSTR CurrentImageName;
  65. LPSTR PlaceFileName;
  66. LPSTR PlaceRootName;
  67. LPSTR ExcludeFileName;
  68. LPSTR DumpOverride = NULL;
  69. LPSTR NormalPlaceSubdir;
  70. LPSTR CommandScriptName;
  71. LPSTR SymbolFilePath = NULL;
  72. LPSTR DestinationPath = NULL;
  73. LPSTR PrivateSymbolFilePath = NULL;
  74. LPSTR BinplaceLcDir;
  75. LPSTR LcFilePart;
  76. LPSTR szRSDSDllToLoad;
  77. LPSTR gNewFileName;
  78. LPSTR gPrivatePdbFullPath=NULL;
  79. LPSTR gPublicPdbFullPath=NULL;
  80. HINF LayoutInf;
  81. FILE *PlaceFile;
  82. FILE *LogFile;
  83. FILE *CommandScriptFile;
  84. CHAR* gDelayLoadModule;
  85. CHAR* gDelayLoadHandler;
  86. CHAR gFullFileName[MAX_PATH+1];
  87. CHAR gDestinationFile[MAX_PATH+1];
  88. UCHAR SetupFilePath[ MAX_PATH+1 ];
  89. UCHAR DebugFilePath[ MAX_PATH+1 ];
  90. UCHAR PlaceFilePath[ MAX_PATH+1 ];
  91. UCHAR ExcludeFilePath[ MAX_PATH+1 ];
  92. UCHAR DefaultSymbolFilePath[ MAX_PATH+1 ];
  93. UCHAR szAltPlaceRoot[ MAX_PATH+1 ];
  94. UCHAR LcFullFileName[ MAX_PATH+1 ];
  95. UCHAR szExtraInfo[4096];
  96. UCHAR TraceFormatFilePath[ MAX_PATH+1 ] ;
  97. UCHAR LastPdbName[ MAX_PATH+1 ] ;
  98. UCHAR TraceDir[ MAX_PATH+1 ] ;
  99. #define DEFAULT_PLACE_FILE "\\tools\\placefil.txt"
  100. #define DEFAULT_NTROOT "\\nt"
  101. #define DEFAULT_NTDRIVE "c:"
  102. #define DEFAULT_DUMP "dump"
  103. #define DEFAULT_LCDIR "LcINF"
  104. #define DEFAULT_EXCLUDE_FILE "\\tools\\symbad.txt"
  105. #define DEFAULT_TRACEDIR "TraceFormat"
  106. #define DEFAULT_DELAYLOADDIR "delayload"
  107. typedef struct _CLASS_TABLE {
  108. LPSTR ClassName;
  109. LPSTR ClassLocation;
  110. } CLASS_TABLE, *PCLASS_TABLE;
  111. BOOL
  112. PlaceTheFile();
  113. BOOL BinplaceGetSourcePdbName(LPTSTR SourceFileName, DWORD BufferSize, CHAR* SourcePdbName, DWORD* PdbSig);
  114. //BOOL FileExists(LPTSTR Filename);
  115. BOOL StripCVSymbolPath (LPSTR DestinationFile); // in StripCVSymbolPath.c
  116. // concat 3 paths together handling the case where the second may be relative to the first
  117. // or may be absolute
  118. BOOL ConcatPaths( LPTSTR pszDest, size_t cbDest, LPCTSTR Root, LPCTSTR Symbols, LPCTSTR Ext);
  119. typedef
  120. BOOL
  121. (WINAPI *PCREATEHARDLINKA)(
  122. LPCSTR lpFileName,
  123. LPCSTR lpExistingFileName,
  124. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  125. );
  126. PCREATEHARDLINKA pCreateHardLinkA;
  127. // Symbol checking
  128. #define MAX_SYM_ERR 500
  129. BOOL
  130. CheckSymbols( // in CheckSymbols.c
  131. LPSTR SourceFileName,
  132. LPSTR TmpPath,
  133. LPSTR ExcludeFileName,
  134. BOOL SymbolFlag,
  135. LPSTR ErrMsg,
  136. size_t ErrMsgLen
  137. );
  138. BOOL
  139. CopyTheFile(
  140. LPSTR SourceFileName,
  141. LPSTR SourceFilePart,
  142. LPSTR DestinationSubdir,
  143. LPSTR DestinationFilePart
  144. );
  145. BOOL
  146. BinplaceCopyPdb (
  147. LPSTR DestinationFile,
  148. LPSTR SourceFileName, // Used for redist case
  149. BOOL CopyFromSourceOnly,
  150. BOOL StripPrivate
  151. );
  152. BOOL
  153. SourceIsNewer( // in SourceIsNewer.c
  154. IN LPSTR SourceFile,
  155. IN LPSTR TargetFile,
  156. IN BOOL fIsWin9x);
  157. /* This is no longer used
  158. __inline BOOL
  159. SearchOneDirectory(
  160. IN LPSTR Directory,
  161. IN LPSTR FileToFind,
  162. IN LPSTR SourceFullName,
  163. IN LPSTR SourceFilePart,
  164. OUT PBOOL FoundInTree
  165. )
  166. {
  167. //
  168. // This was way too slow. Just say we didn't find the file.
  169. //
  170. *FoundInTree = FALSE;
  171. return(TRUE);
  172. }
  173. */
  174. BOOL SignWithIDWKey(IN LPCSTR FileName, IN BOOL fVerbose); // in SignWithIDWKey.c
  175. CLASS_TABLE CommonClassTable[] = {
  176. {"retail", "."},
  177. {"system", "system32"},
  178. {"system16","system"},
  179. {"windows", "."},
  180. {"drivers", "system32\\drivers"},
  181. {"drvetc", "system32\\drivers\\etc"},
  182. {"config", "system32\\config"},
  183. {NULL,NULL}
  184. };
  185. CLASS_TABLE i386SpecificClassTable[] = {
  186. {"hal","system32"},
  187. {"printer","system32\\spool\\drivers\\w32x86"},
  188. {"prtprocs","system32\\spool\\prtprocs\\w32x86"},
  189. {NULL,NULL}
  190. };
  191. CLASS_TABLE Amd64SpecificClassTable[] = {
  192. {"hal",".."},
  193. {"printer","system32\\spool\\drivers\\w32amd64"},
  194. {"prtprocs","system32\\spool\\prtprocs\\w32amd64"},
  195. {NULL,NULL}
  196. };
  197. CLASS_TABLE ia64SpecificClassTable[] = {
  198. {"hal",".."},
  199. {"printer","system32\\spool\\drivers\\w32ia64"},
  200. {"prtprocs","system32\\spool\\prtprocs\\w32ia64"},
  201. {NULL,NULL}
  202. };
  203. DWORD GetAndLogNextArg( OUT TCHAR* Buffer, // local wrapper for GetNextArg()
  204. IN DWORD BufferSize,
  205. OPTIONAL OUT DWORD* RequiredSize);
  206. BOOL PrintMessageLogBuffer(FILE* fLogHandle); // write the buffer to fLogHandle
  207. BOOL FreeMessageLogBuffer(void); // free global arg buffer
  208. int __cdecl
  209. main(
  210. int argc,
  211. char *argv[],
  212. char *envp[]
  213. )
  214. {
  215. BOOL gOnlyCopyArchiveFiles = FALSE;
  216. BOOL fBypassSplitSymX = FALSE;
  217. char c, *p, *OverrideFlags, *s, **newargv=NULL;
  218. LPSTR LcFileName = NULL;
  219. int i, n;
  220. BOOL NoPrivateSplit = FALSE;
  221. OSVERSIONINFO VersionInformation;
  222. LPTSTR platform;
  223. FILE * MsgLogFile;
  224. CHAR * MsgLogFileName;
  225. HANDLE hMutex;
  226. CHAR ArgBuffer[MAX_PATH+1];
  227. DWORD ArgSize = sizeof(ArgBuffer);
  228. DWORD ArgSizeNeeded;
  229. CHAR* PlaceFileNameBuffer = NULL;
  230. CHAR* PlaceRootNameBuffer = NULL;
  231. CHAR CommonTempBuffer[MAX_PATH+1];
  232. CHAR* CommonTempPtr;
  233. gNewFileName = NULL;
  234. ImageCheck.Argv = NULL;
  235. fLogPdbPaths = FALSE;
  236. gPrivatePdbFullPath= (CHAR*)malloc(sizeof(CHAR)*(MAX_PATH+1));
  237. gPublicPdbFullPath = (CHAR*)malloc(sizeof(CHAR)*(MAX_PATH+1));
  238. if (gPrivatePdbFullPath==NULL||gPublicPdbFullPath==NULL) {
  239. fprintf( stderr, "BINPLACE : error BNP0273: out of memory\n");
  240. exit(BINPLACE_ERR);
  241. }
  242. //
  243. // Win 95 can't compare file times very well, this hack neuters the SourceIsNewer function
  244. // on Win 95
  245. //
  246. VersionInformation.dwOSVersionInfoSize = sizeof( VersionInformation );
  247. if (GetVersionEx( &VersionInformation ) && VersionInformation.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  248. fPatheticOS = TRUE;
  249. }
  250. envp;
  251. fUpDriver = FALSE;
  252. fUsage = FALSE;
  253. fVerbose = FALSE;
  254. fSymChecking = FALSE;
  255. fTestMode = FALSE;
  256. fSplitSymbols = FALSE;
  257. fKeepAttributes = FALSE;
  258. fDigitalSign = FALSE;
  259. fHardLinks = FALSE;
  260. fIgnoreHardLinks = FALSE;
  261. fDontExit = FALSE;
  262. fForcePlace = FALSE;
  263. fSignCode = FALSE;
  264. fVerifyLc = FALSE;
  265. fWppFmt = FALSE ;
  266. fSrcControl = FALSE;
  267. fDbgControl = FALSE;
  268. NormalPlaceSubdir = NULL;
  269. pVerifyLocConstraintA = NULL;
  270. if (argc < 2) {
  271. goto showUsage;
  272. }
  273. if ( (szRSDSDllToLoad = (LPSTR) malloc((MAX_PATH+1) * sizeof(CHAR))) == NULL ) {
  274. fprintf( stderr, "BINPLACE : error BNP0322: Out of memory\n");
  275. exit(BINPLACE_ERR);
  276. }
  277. StringCbCopy( szRSDSDllToLoad, (MAX_PATH+1) * sizeof(CHAR), "mspdb70.dll");
  278. setvbuf(stderr, NULL, _IONBF, 0);
  279. setvbuf(stdout, NULL, _IONBF, 0);
  280. if (!(PlaceFileName = getenv( "BINPLACE_PLACEFILE" )) &&
  281. !(PlaceFileName = getenv( "BINPLACE_PLACEFILE_DEFAULT" ))) {
  282. if ((PlaceFileName = getenv("_NTDRIVE")) == NULL) {
  283. PlaceFileName = DEFAULT_NTDRIVE;
  284. }
  285. StringCbCopy((PCHAR) PlaceFilePath, sizeof(PlaceFilePath), PlaceFileName);
  286. if ((PlaceFileName = getenv("_NTROOT")) == NULL) {
  287. PlaceFileName = DEFAULT_NTROOT;
  288. }
  289. StringCbCat((PCHAR) PlaceFilePath, sizeof(PlaceFilePath), PlaceFileName);
  290. StringCbCat((PCHAR) PlaceFilePath, sizeof(PlaceFilePath), DEFAULT_PLACE_FILE);
  291. PlaceFileName = (PCHAR) PlaceFilePath;
  292. }
  293. if (!(ExcludeFileName = getenv( "BINPLACE_EXCLUDE_FILE" ))) {
  294. if ((ExcludeFileName = getenv("_NTDRIVE")) == NULL) {
  295. ExcludeFileName = DEFAULT_NTDRIVE;
  296. }
  297. StringCbCopy((PCHAR) ExcludeFilePath, sizeof(ExcludeFilePath), ExcludeFileName);
  298. if ((ExcludeFileName = getenv("_NTROOT")) == NULL) {
  299. ExcludeFileName = DEFAULT_NTROOT;
  300. }
  301. StringCbCat((PCHAR) ExcludeFilePath, sizeof(ExcludeFilePath), ExcludeFileName);
  302. StringCbCat((PCHAR) ExcludeFilePath, sizeof(ExcludeFilePath), DEFAULT_EXCLUDE_FILE);
  303. ExcludeFileName = (PCHAR) ExcludeFilePath;
  304. }
  305. if (!(BinplaceLcDir = getenv( "BINPLACE_LCDIR" ))) {
  306. BinplaceLcDir = DEFAULT_LCDIR;
  307. }
  308. if ( getenv("NT_SIGNCODE") != NULL ) {
  309. fSignCode=TRUE;
  310. }
  311. //
  312. // Support Cross compile as well
  313. //
  314. #if defined(_AMD64_)
  315. ImageCheck.Machine = IMAGE_FILE_MACHINE_AMD64;
  316. PlaceRootName = getenv( "_NTAMD64TREE" );
  317. #elif defined(_IA64_)
  318. ImageCheck.Machine = IMAGE_FILE_MACHINE_IA64;
  319. PlaceRootName = getenv( "_NTIA64TREE" );
  320. #else // defined(_X86_)
  321. if ((platform = getenv("AMD64")) != NULL) {
  322. ImageCheck.Machine = IMAGE_FILE_MACHINE_AMD64;
  323. PlaceRootName = getenv( "_NTAMD64TREE" );
  324. } else if ((platform = getenv("IA64")) != NULL) {
  325. ImageCheck.Machine = IMAGE_FILE_MACHINE_IA64;
  326. PlaceRootName = getenv( "_NTIA64TREE" );
  327. } else {
  328. ImageCheck.Machine = IMAGE_FILE_MACHINE_I386;
  329. PlaceRootName = getenv( "_NT386TREE" );
  330. if (!PlaceRootName)
  331. PlaceRootName = getenv( "_NTx86TREE" );
  332. }
  333. #endif
  334. CurrentImageName = NULL;
  335. OverrideFlags = getenv( "BINPLACE_OVERRIDE_FLAGS" );
  336. if (OverrideFlags != NULL) {
  337. s = OverrideFlags;
  338. n = 0;
  339. while (*s) {
  340. while (*s && *s <= ' ')
  341. s += 1;
  342. if (*s) {
  343. n += 1;
  344. while (*s > ' ')
  345. s += 1;
  346. if (*s)
  347. *s++ = '\0';
  348. }
  349. }
  350. if (n) {
  351. newargv = malloc( (argc + n + 1) * sizeof( char * ) );
  352. memcpy( &newargv[n], argv, argc * sizeof( char * ) );
  353. argv = newargv;
  354. argv[ 0 ] = argv[ n ];
  355. argc += n;
  356. s = OverrideFlags;
  357. for (i=1; i<=n; i++) {
  358. while (*s && *s <= ' ')
  359. s += 1;
  360. argv[ i ] = s;
  361. while (*s++)
  362. ;
  363. }
  364. __argv = argv; // required for GetNextArg()
  365. __argc = argc;
  366. }
  367. }
  368. // skip past exe name and don't log it
  369. GetNextArg(CommonTempBuffer, sizeof(CommonTempBuffer), NULL);
  370. while ( (ArgSizeNeeded = GetAndLogNextArg(ArgBuffer, ArgSize, NULL)) != 0 ) {
  371. p = ArgBuffer;
  372. if (*p == '/' || *p == '-') {
  373. if (_stricmp(p + 1, "ChangeAsmsToRetailForSymbols") == 0) {
  374. fChangeAsmsToRetailForSymbols = TRUE;
  375. } else {
  376. while (c = *++p)
  377. switch (toupper( c )) {
  378. case '?':
  379. fUsage = TRUE;
  380. break;
  381. case 'A':
  382. SplitFlags |= SPLITSYM_EXTRACT_ALL;
  383. break;
  384. case 'B':
  385. CommonTempPtr = (CHAR*)realloc(NormalPlaceSubdir, GetNextArgSize()*sizeof(CHAR));
  386. if (CommonTempPtr==NULL) {
  387. exit(BINPLACE_ERR);
  388. }
  389. NormalPlaceSubdir = CommonTempPtr;
  390. GetAndLogNextArg(NormalPlaceSubdir, _msize(NormalPlaceSubdir), NULL);
  391. break;
  392. case 'C':
  393. if (*(p+1) == 'I' || *(p+1) == 'i') {
  394. char *q;
  395. GetAndLogNextArg(CommonTempBuffer, sizeof(CommonTempBuffer), NULL);
  396. p = CommonTempBuffer;
  397. ImageCheck.RC = atoi(p);
  398. if (!ImageCheck.RC) {
  399. fprintf( stderr, "BINPLACE : error BNP0000: Invalid return code for -CI option\n");
  400. fUsage = TRUE;
  401. }
  402. while (*p++ != ',');
  403. q = p;
  404. ImageCheck.Argc = 0;
  405. while (*p != '\0')
  406. if (*p++ == ',') ImageCheck.Argc++;
  407. // last option plus extra args for Image file and Argv NULL
  408. ImageCheck.Argc += 3;
  409. ImageCheck.Argv = malloc( ImageCheck.Argc * sizeof( void * ) );
  410. for ( i = 0; i <= ImageCheck.Argc - 3; i++) {
  411. ImageCheck.Argv[i] = q;
  412. while (*q != ',' && *q != '\0') q++;
  413. *q++ = '\0';
  414. }
  415. p--;
  416. ImageCheck.Argv[ImageCheck.Argc-1] = NULL;
  417. } else {
  418. fDigitalSign = TRUE;
  419. }
  420. break;
  421. case 'D':
  422. if (*(p+1) == 'L' || *(p+1) == 'l')
  423. {
  424. GetAndLogNextArg(CommonTempBuffer, sizeof(CommonTempBuffer), NULL);
  425. p = CommonTempBuffer;
  426. gDelayLoadModule = p;
  427. while (*p != ',')
  428. {
  429. p++;
  430. }
  431. *p = '\0';
  432. p++;
  433. gDelayLoadHandler = p;
  434. while (*p != '\0')
  435. {
  436. p++;
  437. }
  438. p--;
  439. if (gDelayLoadModule[0] == '\0' ||
  440. gDelayLoadHandler[0] == '\0')
  441. {
  442. fprintf(stderr, "BINPLACE : error BNP0000: Invalid switch for -dl option\n");
  443. fUsage = TRUE;
  444. }
  445. else
  446. {
  447. fCheckDelayload = TRUE;
  448. }
  449. }
  450. else
  451. {
  452. CommonTempPtr = (CHAR*)realloc(DumpOverride,GetNextArgSize()*sizeof(CHAR));
  453. if (CommonTempPtr==NULL) {
  454. exit(BINPLACE_ERR);
  455. }
  456. DumpOverride = CommonTempPtr;
  457. GetAndLogNextArg(DumpOverride, _msize(DumpOverride), NULL);
  458. }
  459. break;
  460. case 'E':
  461. fDontExit = TRUE;
  462. break;
  463. case 'F':
  464. fForcePlace = TRUE;
  465. break;
  466. case 'G':
  467. CommonTempPtr = (CHAR*)realloc(LcFileName,GetNextArgSize()*sizeof(CHAR));
  468. if (CommonTempPtr==NULL) {
  469. exit(BINPLACE_ERR);
  470. }
  471. LcFileName = CommonTempPtr;
  472. GetAndLogNextArg(LcFileName, _msize(LcFileName), NULL);
  473. break;
  474. case 'H':
  475. if ((VersionInformation.dwPlatformId != VER_PLATFORM_WIN32_NT) ||
  476. (VersionInformation.dwMajorVersion < 5) ||
  477. (pCreateHardLinkA = (PCREATEHARDLINKA)GetProcAddress( GetModuleHandle( "KERNEL32" ),
  478. "CreateHardLinkA"
  479. )
  480. ) == NULL
  481. ) {
  482. fprintf( stderr, "BINPLACE: Hard links not supported. Defaulting to CopyFile\n" );
  483. fHardLinks = FALSE;
  484. } else {
  485. fHardLinks = TRUE;
  486. }
  487. break;
  488. case 'J':
  489. fSymChecking = TRUE;
  490. break;
  491. case 'K':
  492. fKeepAttributes = TRUE;
  493. break;
  494. case 'L':
  495. break;
  496. case 'M':
  497. fMakeErrorOnDumpCopy = TRUE;
  498. break;
  499. case 'N':
  500. CommonTempPtr = (CHAR*)realloc(PrivateSymbolFilePath,GetNextArgSize()*sizeof(CHAR));
  501. if (CommonTempPtr==NULL) {
  502. exit(BINPLACE_ERR);
  503. }
  504. PrivateSymbolFilePath = CommonTempPtr;
  505. GetAndLogNextArg(PrivateSymbolFilePath, _msize(PrivateSymbolFilePath), NULL);
  506. break;
  507. case 'O':
  508. if (PlaceRootName != NULL) {
  509. StringCbCopy(szAltPlaceRoot, sizeof(szAltPlaceRoot), PlaceRootName);
  510. StringCbCat( szAltPlaceRoot, sizeof(szAltPlaceRoot), "\\");
  511. // concat next arg to the end of szAltPlaceRoot
  512. GetAndLogNextArg( &szAltPlaceRoot[strlen(szAltPlaceRoot)],
  513. (sizeof(szAltPlaceRoot)/sizeof(CHAR)) - strlen(szAltPlaceRoot),
  514. NULL);
  515. PlaceRootName = szAltPlaceRoot;
  516. }
  517. break;
  518. case 'P':
  519. CommonTempPtr = (CHAR*)realloc(PlaceFileNameBuffer,GetNextArgSize()*sizeof(CHAR));
  520. if (CommonTempPtr==NULL) {
  521. exit(BINPLACE_ERR);
  522. }
  523. PlaceFileNameBuffer = CommonTempPtr;
  524. GetAndLogNextArg(PlaceFileNameBuffer, _msize(PlaceFileNameBuffer), NULL);
  525. PlaceFileName = PlaceFileNameBuffer;
  526. break;
  527. case 'Q':
  528. fDontLog = TRUE;
  529. break;
  530. case 'R':
  531. CommonTempPtr = (CHAR*)realloc(PlaceRootNameBuffer,GetNextArgSize()*sizeof(CHAR));
  532. if (CommonTempPtr==NULL) {
  533. exit(BINPLACE_ERR);
  534. }
  535. PlaceRootNameBuffer = CommonTempPtr;
  536. GetAndLogNextArg(PlaceRootNameBuffer, _msize(PlaceRootNameBuffer), NULL);
  537. PlaceRootName = PlaceRootNameBuffer;
  538. break;
  539. case 'S':
  540. CommonTempPtr = (CHAR*)realloc(SymbolFilePath,GetNextArgSize()*sizeof(CHAR));
  541. if (CommonTempPtr==NULL) {
  542. exit(BINPLACE_ERR);
  543. }
  544. SymbolFilePath = CommonTempPtr;
  545. GetAndLogNextArg(SymbolFilePath, _msize(SymbolFilePath), NULL);
  546. fSplitSymbols = TRUE;
  547. fIgnoreHardLinks = TRUE;
  548. break;
  549. case 'T':
  550. fTestMode = TRUE;
  551. break;
  552. case 'U':
  553. fBypassSplitSymX = TRUE;
  554. fUpDriver = TRUE;
  555. break;
  556. case 'V':
  557. fVerbose = TRUE;
  558. break;
  559. case 'W':
  560. fPlaceWin95SymFile = TRUE;
  561. break;
  562. case 'X':
  563. SplitFlags |= SPLITSYM_REMOVE_PRIVATE;
  564. break;
  565. case 'Y':
  566. fNoClassInSymbolsDir = TRUE;
  567. break;
  568. case 'Z':
  569. NoPrivateSplit = TRUE;
  570. break;
  571. case ':': // Simple (== crude) escape mechanism as all the letters are used
  572. // -:XXX can add extra options if need be
  573. // For now just handle TMF, Trace Message Format processing of PDB's
  574. if ((strlen(p) >= 3) && ((toupper(*(p+1)) == 'T') && (toupper(*(p+2)) == 'M') && (toupper(*(p+3))) == 'F')) {
  575. LPSTR tfile ;
  576. // If the RUNWPP operation ran this option will be automatically added
  577. p += 3 ; // Gobble up the TMF
  578. fBypassSplitSymX = TRUE; // SplitSymbolsX() causes problems when used with -:TMF
  579. fWppFmt = TRUE ; // Need to package up the Software Tracing Formats
  580. strncpy(TraceDir,DEFAULT_TRACEDIR,MAX_PATH) ; //Append to PrivateSymbolsPath
  581. //If no default override.
  582. tfile = getenv("TRACE_FORMAT_PATH"); //Has Path been overriden?
  583. if (tfile != NULL) {
  584. StringCbPrintfA(TraceFormatFilePath, sizeof(TraceFormatFilePath), "%s", tfile);
  585. if (fVerbose) {
  586. fprintf( stdout, "BINPLACE : warning BNP0000: Trace Formats file path set to %s\n", TraceFormatFilePath ) ;
  587. }
  588. } else {
  589. TraceFormatFilePath[0] = '\0' ;
  590. }
  591. } else if ((strlen(p) >= 3) && ((toupper(*(p+1)) == 'S') && (toupper(*(p+2)) == 'R') && (toupper(*(p+3))) == 'C')) {
  592. // This is the option for turning on creating a cvdump for the pdb for
  593. // source control.
  594. p += 3;
  595. fSrcControl=TRUE;
  596. } else if ((strlen(p) >= 3) && ((toupper(*(p+1)) == 'R') && (toupper(*(p+2)) == 'E') && (toupper(*(p+3))) == 'N')) {
  597. // cmdline file renaming
  598. p += 3;
  599. CommonTempPtr = (CHAR*)realloc(gNewFileName,GetNextArgSize()*sizeof(CHAR));
  600. if (CommonTempPtr==NULL) {
  601. exit(BINPLACE_ERR);
  602. }
  603. gNewFileName = CommonTempPtr;
  604. GetAndLogNextArg(gNewFileName, _msize(gNewFileName), NULL);
  605. } else if ((strlen(p) >= 3) && ((toupper(*(p+1)) == 'D') && (toupper(*(p+2)) == 'B') && (toupper(*(p+3))) == 'G')) {
  606. // This is the option for turning on creating a cvdump for the pdb for
  607. // source control.
  608. p += 3;
  609. fDbgControl=TRUE;
  610. } else if ((strlen(p) >= 3) && ((toupper(*(p+1)) == 'A') && (toupper(*(p+2)) == 'R') && (toupper(*(p+3))) == 'C')) {
  611. // only binplace the file if the ARCHIVE attribute is set
  612. p += 3;
  613. gOnlyCopyArchiveFiles=TRUE;
  614. } else if ((strlen(p) == 5) && ((toupper(*(p+1)) == 'D') &&
  615. (toupper(*(p+2)) == 'E') &&
  616. (toupper(*(p+3)) == 'S') &&
  617. (toupper(*(p+4)) == 'T'))) {
  618. p += 4;
  619. CommonTempPtr = (CHAR*)realloc(DestinationPath,GetNextArgSize()*sizeof(CHAR));
  620. if (CommonTempPtr==NULL) {
  621. exit(BINPLACE_ERR);
  622. }
  623. DestinationPath = CommonTempPtr;
  624. GetAndLogNextArg(DestinationPath, _msize(DestinationPath), NULL);
  625. } else if ((strlen(p) == 7) && ((toupper(*(p+1)) == 'L') &&
  626. (toupper(*(p+2)) == 'O') &&
  627. (toupper(*(p+3)) == 'G') &&
  628. (toupper(*(p+4)) == 'P') &&
  629. (toupper(*(p+5)) == 'D') &&
  630. (toupper(*(p+6)) == 'B'))) {
  631. fLogPdbPaths = TRUE;
  632. p+=6;
  633. }
  634. break;
  635. default:
  636. fprintf( stderr, "BINPLACE : error BNP0000: Invalid switch - /%c\n", c );
  637. fUsage = TRUE;
  638. break;
  639. }
  640. }
  641. if ( fUsage ) {
  642. showUsage:
  643. fputs(
  644. "usage: binplace [switches] image-names... \n"
  645. "where: [-?] display this message\n"
  646. " [-a] Used with -s, extract all symbols\n"
  647. " [-b subdir] put file in subdirectory of normal place\n"
  648. " [-c] digitally sign image with IDW key\n"
  649. " [-d dump-override]\n"
  650. " [-:DBG] Don't binplace DBG files. If -j is present, don't binplace \n"
  651. " binaries that point to DBG files.\n"
  652. " [-:DEST <class>] Don't bother with placefil.txt - just put the\n"
  653. " file(s) in the destination specified\n"
  654. " [-e] don't exit if a file in list could not be binplaced\n"
  655. " [-f] force placement by disregarding file timestamps\n"
  656. " [-g lc-file] verify image with localization constraint file\n"
  657. " [-h] modifies behavior to use hard links instead of CopyFile.\n"
  658. " (ignored if -s is present)\n"
  659. " [-j] verify proper symbols exist before copying\n"
  660. " [-k] keep attributes (don't turn off archive)\n"
  661. " [-:LOGPDB] include PDB paths in binplace.log\n"
  662. " [-m] binplace files to dump (generates an error also)\n"
  663. " [-n <Path>] Used with -x - Private pdb symbol path\n"
  664. " [-o place-root-subdir] alternate project subdirectory\n"
  665. " [-p place-file]\n"
  666. " [-q] suppress writing to log file %BINPLACE_LOG%\n"
  667. " [-r place-root]\n"
  668. " [-s Symbol file path] split symbols from image files\n"
  669. " [-:SRC] Process the PDB for source indexing\n"
  670. " [-t] test mode\n"
  671. " [-:TMF] Process the PDB for Trace Format files\n"
  672. " [-u] UP driver\n"
  673. " [-v] verbose output\n"
  674. " [-w] copy the Win95 Sym file to the symbols tree\n"
  675. " [-x] Used with -s, delete private symbolic when splitting\n"
  676. " [-y] Used with -s, don't create class subdirs in the symbols tree\n"
  677. " [-z] ignore -x if present\n"
  678. " [-ci <rc,app,-arg0,-argv1,-argn>]\n"
  679. " rc=application error return code,\n"
  680. " app=application used to check images,\n"
  681. " -arg0..-argn=application options\n"
  682. " [-dl <modulename,delay-load handler>] (run dlcheck on this file)\n"
  683. "\n"
  684. "BINPLACE looks for the following environment variable names:\n"
  685. " BINPLACE_EXCLUDE_FILE - full path name to symbad.txt\n"
  686. " BINPLACE_OVERRIDE_FLAGS - may contain additional switches\n"
  687. " BINPLACE_PLACEFILE - default value for -p flag\n"
  688. " _NT386TREE - default value for -r flag on x86 platform\n"
  689. " _NTAMD64TREE - default value for -r flag on AMD64 platform\n"
  690. " _NTIA64TREE - default value for -r flag on IA64 platform\n"
  691. " TRACE_FORMAT_PATH - set the path for Trace Format Files\n"
  692. "\n"
  693. ,stderr
  694. );
  695. exit(BINPLACE_ERR);
  696. }
  697. } else {
  698. WIN32_FIND_DATA FindData;
  699. HANDLE h;
  700. gPrivatePdbFullPath[0]= '\0';
  701. gPublicPdbFullPath[0] = '\0';
  702. if (!PlaceRootName) {
  703. // If there's no root, just exit.
  704. exit(BINPLACE_OK);
  705. }
  706. //
  707. // Workaround for bogus setargv: ignore directories
  708. //
  709. if (NoPrivateSplit) {
  710. SplitFlags &= ~SPLITSYM_REMOVE_PRIVATE;
  711. }
  712. h = FindFirstFile(p,&FindData);
  713. if (h != INVALID_HANDLE_VALUE) {
  714. FindClose(h);
  715. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  716. if ( fVerbose ) {
  717. fprintf(stdout,"BINPLACE : warning BNP0000: ignoring directory %s\n",p);
  718. }
  719. continue;
  720. }
  721. if (gOnlyCopyArchiveFiles) {
  722. if (! (FindData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ) {
  723. if ( fVerbose ) {
  724. fprintf(stdout,"BINPLACE : warning BNP1009: ignoring file without archive attribute %s\n",p);
  725. }
  726. continue;
  727. }
  728. }
  729. }
  730. CurrentImageName = p;
  731. // If this is a dbg, don't binplace it
  732. if ( fDbgControl && (strlen(p) > 4) &&
  733. (strcmp(p+strlen(p)-4, ".dbg")== 0 ) ) {
  734. fprintf(stderr, "BINPLACE : warning BNP0000: Dbg files not allowed. Use dbgtopdb.exe to remove %s.\n",p);
  735. // exit(BINPLACE_ERR);
  736. }
  737. //
  738. // If the master place file has not been opened, open
  739. // it up.
  740. //
  741. if ( !PlaceFile && !DestinationPath) {
  742. PlaceFile = fopen(PlaceFileName, "rt");
  743. if (!PlaceFile) {
  744. fprintf(stderr,"BINPLACE : fatal error BNP0000: fopen of placefile %s failed %d\n",PlaceFileName,GetLastError());
  745. exit(BINPLACE_ERR);
  746. }
  747. }
  748. //
  749. // Check for bogus -g lc-file switch
  750. //
  751. if ( LcFileName != NULL ) {
  752. h = FindFirstFile(LcFileName, &FindData);
  753. if (h == INVALID_HANDLE_VALUE ||
  754. (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  755. if (fVerbose ) {
  756. fprintf(stdout,"BINPLACE : warning BNP0000: invalid file %s. Ignoring -G switch.\n", LcFileName);
  757. }
  758. LcFileName = NULL;
  759. }
  760. if (h != INVALID_HANDLE_VALUE) {
  761. FindClose(h);
  762. }
  763. }
  764. if ( LcFileName != NULL ) {
  765. DWORD cb = GetFullPathName(LcFileName,MAX_PATH+1,LcFullFileName,&LcFilePart);
  766. if (!cb || cb > MAX_PATH+1) {
  767. fprintf(stderr,"BINPLACE : fatal error BNP0000: GetFullPathName %s failed %d\n",LcFileName, GetLastError());
  768. exit(BINPLACE_ERR);
  769. }
  770. hLcManager = LoadLibraryA("lcman.DLL");
  771. if (hLcManager != NULL) {
  772. (VOID *) pVerifyLocConstraintA = GetProcAddress(hLcManager, "VerifyLocConstraintA");
  773. }
  774. if (pVerifyLocConstraintA != NULL) {
  775. fVerifyLc = TRUE;
  776. } else {
  777. fprintf(stdout,"BINPLACE : warning BNP0000: Unable to bind to the necessary LCMAN.DLL functions... Ignoring -G switch\n");
  778. }
  779. }
  780. if (PlaceRootName == NULL) {
  781. fprintf(stderr,"BINPLACE : fatal error BNP0000: Place Root not defined - exiting.\n");
  782. exit(BINPLACE_ERR);
  783. }
  784. // If the SymbolFilePath has not been set, make a default value.
  785. if (!SymbolFilePath) {
  786. StringCbCopy(DefaultSymbolFilePath, sizeof(DefaultSymbolFilePath), PlaceRootName);
  787. StringCbCat( DefaultSymbolFilePath, sizeof(DefaultSymbolFilePath), "\\symbols");
  788. SymbolFilePath = DefaultSymbolFilePath;
  789. }
  790. if ( !PlaceTheFile() ) {
  791. if (fDontExit) {
  792. fprintf(stderr,"BINPLACE : error BNP0000: Unable to place file %s.\n",CurrentImageName);
  793. } else {
  794. fprintf(stderr,"BINPLACE : fatal error BNP0000: Unable to place file %s - exiting.\n",CurrentImageName);
  795. exit(BINPLACE_ERR);
  796. }
  797. } else {
  798. }
  799. }
  800. }
  801. if ( (MsgLogFileName = getenv("BINPLACE_MESSAGE_LOG")) != NULL) {
  802. if (!MakeSureDirectoryPathExists(MsgLogFileName)) {
  803. fprintf(stderr,"BINPLACE : error BNP0108: Unable to make directory to \"%s\"\n", MsgLogFileName);
  804. } else {
  805. hMutex = CreateMutex(NULL, FALSE, "WRITE_BINPLACE_MESSAGE_LOG");
  806. if (hMutex != NULL) {
  807. if ( WaitForSingleObject(hMutex, INFINITE) != WAIT_FAILED ) {
  808. MsgLogFile = fopen(MsgLogFileName, "a");
  809. if ( !MsgLogFile ) {
  810. fprintf(stderr,"BINPLACE : error BNP0109: fopen of log file %s failed %d\n", MsgLogFileName,GetLastError());
  811. } else {
  812. setvbuf(MsgLogFile, NULL, _IONBF, 0);
  813. PrintMessageLogBuffer(MsgLogFile);
  814. fclose(MsgLogFile);
  815. }
  816. ReleaseMutex(hMutex);
  817. CloseHandle(hMutex);
  818. } else {
  819. fprintf(stderr,"BINPLACE : error BNP0997: failed to acquire mutex (error code 0x%x)\n", GetLastError());
  820. }
  821. } // hMutex != NULL
  822. }
  823. } // getenv("BINPLACE_MESSAGE_LOG")
  824. FreeMessageLogBuffer();
  825. #define SafeFree(a) if (a!=NULL) { free(a); a=NULL; }
  826. SafeFree(NormalPlaceSubdir);
  827. SafeFree(DestinationPath);
  828. SafeFree(gNewFileName);
  829. SafeFree(PrivateSymbolFilePath);
  830. SafeFree(LcFileName);
  831. SafeFree(PlaceRootNameBuffer);
  832. SafeFree(PlaceFileNameBuffer);
  833. SafeFree(DumpOverride);
  834. SafeFree(szRSDSDllToLoad);
  835. SafeFree(ImageCheck.Argv);
  836. SafeFree(newargv);
  837. if (SymbolFilePath != DefaultSymbolFilePath) {
  838. SafeFree(SymbolFilePath);
  839. }
  840. if (PlaceFile)
  841. fclose(PlaceFile);
  842. exit(BINPLACE_OK);
  843. return BINPLACE_OK;
  844. }
  845. CHAR PlaceFileDir[ BINPLACE_FULL_MAX_PATH];
  846. CHAR PlaceFileClass[BINPLACE_FULL_MAX_PATH];
  847. CHAR PlaceFileEntry[BINPLACE_FULL_MAX_PATH];
  848. BOOL
  849. PlaceTheFile()
  850. {
  851. CHAR FullFileName[MAX_PATH+1];
  852. LPSTR PlaceFileNewName;
  853. LPSTR FilePart;
  854. LPSTR Separator;
  855. LPSTR PlaceFileClassPart;
  856. DWORD cb;
  857. int cfield;
  858. PCLASS_TABLE ClassTablePointer;
  859. BOOLEAN ClassMatch;
  860. BOOL fCopyResult;
  861. LPSTR Extension;
  862. BOOL PutInDump;
  863. BOOL PutInDebug = FALSE;
  864. BOOL PutInLcDir = FALSE;
  865. cb = GetFullPathName(CurrentImageName,MAX_PATH+1,FullFileName,&FilePart);
  866. if (!cb || cb > MAX_PATH+1) {
  867. fprintf(stderr,"BINPLACE : fatal error BNP0000: GetFullPathName failed %d\n",GetLastError());
  868. return FALSE;
  869. }
  870. if (!fDontLog) {
  871. StringCbCopy(gFullFileName,sizeof(gFullFileName),FullFileName);
  872. }
  873. if (fVerbose) {
  874. fprintf(stdout,"BINPLACE : warning BNP0000: Looking at file %s\n",FilePart);
  875. }
  876. Extension = strrchr(FilePart,'.');
  877. if (Extension) {
  878. if (!_stricmp(Extension,".DBG")) {
  879. PutInDebug = TRUE;
  880. }
  881. else if (!_stricmp(Extension,".LC")) {
  882. PutInLcDir = TRUE;
  883. }
  884. }
  885. if (!DumpOverride) {
  886. if (DestinationPath) {
  887. StringCbCopy(PlaceFileClass, sizeof(PlaceFileClass), DestinationPath);
  888. if (gNewFileName!=NULL) {
  889. PlaceFileNewName=gNewFileName;
  890. } else {
  891. PlaceFileNewName=NULL;
  892. }
  893. goto DoTheWork;
  894. }
  895. if (fseek(PlaceFile,0,SEEK_SET)) {
  896. fprintf(stderr,"BINPLACE : fatal error BNP0000: fseek(PlaceFile,0,SEEK_SET) failed %d\n",GetLastError());
  897. return FALSE;
  898. }
  899. while (fgets(PlaceFileEntry,sizeof(PlaceFileDir),PlaceFile)) {
  900. PlaceFileClass[0] = '\0';
  901. if( PlaceFileMatch( FullFileName, // IN
  902. PlaceFileEntry, // INOUT
  903. PlaceFileClass, // OUT, assumed CHAR[BINPLACE_MAX_FULL_PATH]
  904. &PlaceFileNewName // OUT
  905. )) {
  906. DoTheWork:
  907. //
  908. // now that we have the file and class, search the
  909. // class tables for the directory.
  910. //
  911. Separator = PlaceFileClass - 1;
  912. while (Separator) {
  913. PlaceFileClassPart = Separator+1;
  914. Separator = strchr(PlaceFileClassPart,':');
  915. if (Separator) {
  916. *Separator = '\0';
  917. }
  918. //
  919. // If the class is "retail" and we're in Setup mode,
  920. // handle this file specially. Setup mode is used to
  921. // incrementally binplace files into an existing installation.
  922. //
  923. SetupFilePath[0] = '\0';
  924. PlaceFileDir[0]='\0';
  925. ClassMatch = FALSE;
  926. ClassTablePointer = &CommonClassTable[0];
  927. while (ClassTablePointer->ClassName) {
  928. if (!_stricmp(ClassTablePointer->ClassName,PlaceFileClassPart)) {
  929. StringCbCopy(PlaceFileDir,sizeof(PlaceFileDir),ClassTablePointer->ClassLocation);
  930. ClassMatch = TRUE;
  931. //
  932. // If the class is a driver and a UP driver is
  933. // specified, then put the driver in the UP
  934. // subdirectory.
  935. //
  936. // Do the same for retail. We assume the -u switch is passed
  937. // only when actually needed.
  938. //
  939. if (fUpDriver
  940. && ( !_stricmp(PlaceFileClass,"drivers")
  941. || !_stricmp(PlaceFileClass,"retail"))) {
  942. StringCbCat(PlaceFileDir,sizeof(PlaceFileDir),"\\up");
  943. }
  944. break;
  945. }
  946. ClassTablePointer++;
  947. }
  948. if (!ClassMatch) {
  949. //
  950. // Search Specific classes
  951. //
  952. // We need to support cross compiling here.
  953. LPTSTR platform;
  954. #if defined(_AMD64_)
  955. ClassTablePointer = &Amd64SpecificClassTable[0];
  956. #elif defined(_IA64_)
  957. ClassTablePointer = &ia64SpecificClassTable[0];
  958. #else // defined(_X86_)
  959. ClassTablePointer = &i386SpecificClassTable[0];
  960. if ((platform = getenv("AMD64")) != NULL) {
  961. ClassTablePointer = &Amd64SpecificClassTable[0];
  962. } else if ((platform = getenv("IA64")) != NULL) {
  963. ClassTablePointer = &ia64SpecificClassTable[0];
  964. }
  965. #endif
  966. while (ClassTablePointer->ClassName) {
  967. if (!_stricmp(ClassTablePointer->ClassName,PlaceFileClassPart)) {
  968. StringCbCopy(PlaceFileDir,sizeof(PlaceFileDir),ClassTablePointer->ClassLocation);
  969. ClassMatch = TRUE;
  970. break;
  971. }
  972. ClassTablePointer++;
  973. }
  974. }
  975. if (!ClassMatch) {
  976. char * asterisk;
  977. //
  978. // Still not found in class table. Use the class as the
  979. // directory
  980. //
  981. if ( fVerbose ) {
  982. fprintf(stderr,"BINPLACE : warning BNP0000: Class %s Not found in Class Tables\n",PlaceFileClassPart);
  983. }
  984. if ( asterisk = strchr( PlaceFileClassPart, '*')) {
  985. //
  986. // Expand * to platform
  987. //
  988. LPTSTR platform;
  989. ULONG PlatformSize;
  990. LPTSTR PlatformPath;
  991. #if defined(_AMD64_)
  992. PlatformSize = 5;
  993. PlatformPath = TEXT("amd64");
  994. #elif defined(_IA64_)
  995. PlatformSize = 4;
  996. PlatformPath = TEXT("ia64");
  997. #else // defined(_X86_)
  998. PlatformSize = 4;
  999. PlatformPath = TEXT("i386");
  1000. if ((platform = getenv("IA64")) != NULL) {
  1001. PlatformPath = TEXT("ia64");
  1002. } else if ((platform = getenv("AMD64")) != NULL) {
  1003. PlatformSize = 5;
  1004. PlatformPath = TEXT("amd64");
  1005. }
  1006. #endif
  1007. *asterisk = '\0';
  1008. StringCbCopy(PlaceFileDir, sizeof(PlaceFileDir), PlaceFileClassPart);
  1009. *asterisk = '*';
  1010. StringCbCat( PlaceFileDir, sizeof(PlaceFileDir), PlatformPath);
  1011. StringCbCat( PlaceFileDir, sizeof(PlaceFileDir), asterisk + 1);
  1012. } else {
  1013. StringCbCopy(PlaceFileDir, sizeof(PlaceFileDir), PlaceFileClassPart);
  1014. }
  1015. }
  1016. if (SetupFilePath[0] == '\0') {
  1017. StringCbCopy(SetupFilePath, sizeof(SetupFilePath), PlaceFileDir);
  1018. StringCbCat( SetupFilePath, sizeof(SetupFilePath), "\\");
  1019. StringCbCat( SetupFilePath, sizeof(SetupFilePath), FilePart);
  1020. }
  1021. if (NormalPlaceSubdir) {
  1022. StringCbCat(PlaceFileDir, sizeof(PlaceFileDir), "\\");
  1023. StringCbCat(PlaceFileDir, sizeof(PlaceFileDir), NormalPlaceSubdir);
  1024. }
  1025. fCopyResult = CopyTheFile(FullFileName,FilePart,PlaceFileDir,PlaceFileNewName);
  1026. if (!fCopyResult) {
  1027. break;
  1028. }
  1029. if ( !fDontLog ) {
  1030. int len = 0;
  1031. LPSTR LogFileName = NULL;
  1032. HANDLE hMutex;
  1033. time_t Time;
  1034. FILE *fSlmIni;
  1035. UCHAR szProject[MAX_PATH];
  1036. UCHAR szSlmServer[MAX_PATH];
  1037. UCHAR szEnlistment[MAX_PATH];
  1038. UCHAR szSlmDir[MAX_PATH];
  1039. UCHAR *szTime="";
  1040. UCHAR szFullDestName[MAX_PATH+1];
  1041. LPSTR szDestFile;
  1042. // Get some other interesting info.
  1043. fSlmIni = fopen("slm.ini", "r");
  1044. if (fSlmIni) {
  1045. fgets(szProject, sizeof(szProject), fSlmIni);
  1046. fgets(szSlmServer, sizeof(szSlmServer), fSlmIni);
  1047. fgets(szEnlistment, sizeof(szEnlistment), fSlmIni);
  1048. fgets(szSlmDir, sizeof(szSlmDir), fSlmIni);
  1049. // Get rid of the trailing newlines
  1050. szProject[strlen(szProject)-1] = '\0';
  1051. szSlmServer[strlen(szSlmServer)-1] = '\0';
  1052. szSlmDir[strlen(szSlmDir)-1] = '\0';
  1053. fclose(fSlmIni);
  1054. } else {
  1055. szSlmServer[0] = '\0';
  1056. szProject[0] = '\0';
  1057. szSlmDir[0] = '\0';
  1058. }
  1059. Time = time(NULL);
  1060. szTime = ctime(&Time);
  1061. // Remove the built-in CR / NewLine
  1062. szTime[ strlen(szTime) - 1 ] = '\0';
  1063. StringCbPrintfA(szExtraInfo, sizeof(szExtraInfo),
  1064. "%s\t%s\t%s\t%s",
  1065. szSlmServer,
  1066. szProject,
  1067. szSlmDir,
  1068. szTime);
  1069. // Generate full path to destination
  1070. szFullDestName[0] = '\0';
  1071. GetFullPathName( gDestinationFile, MAX_PATH + 1, szFullDestName, &szDestFile );
  1072. if ((LogFileName = getenv("BINPLACE_LOG")) != NULL) {
  1073. if (!MakeSureDirectoryPathExists(LogFileName)) {
  1074. fprintf(stderr,"BINPLACE : error BNP0000: Unable to make directory to \"%s\"\n", LogFileName);
  1075. }
  1076. hMutex = CreateMutex(NULL, FALSE, "WRITE_BINPLACE_LOG");
  1077. if (hMutex != NULL) {
  1078. if ( WaitForSingleObject(hMutex, INFINITE) != WAIT_FAILED ) {
  1079. LogFile = fopen(LogFileName, "a");
  1080. if ( !LogFile ) {
  1081. fprintf(stderr,"BINPLACE : error BNP0110: fopen of log file %s failed %d\n", LogFileName,GetLastError());
  1082. } else {
  1083. setvbuf(LogFile, NULL, _IONBF, 0);
  1084. if ( fLogPdbPaths ) {
  1085. len = fprintf(LogFile,"%s\t%s\t%s\t%s\t%s\n",gFullFileName,szExtraInfo,szFullDestName,gPublicPdbFullPath,gPrivatePdbFullPath);
  1086. } else {
  1087. len = fprintf(LogFile,"%s\t%s\t%s\n",gFullFileName,szExtraInfo,szFullDestName);
  1088. }
  1089. if ( len < 0 ) {
  1090. fprintf(stderr,"BINPLACE : error BNP0000: write to log file %s failed %d\n", LogFileName, GetLastError());
  1091. }
  1092. fclose(LogFile);
  1093. }
  1094. ReleaseMutex(hMutex);
  1095. CloseHandle(hMutex);
  1096. } else {
  1097. fprintf(stderr,"BINPLACE : error BNP0970: failed to acquire mutex (error code 0x%x)\n", GetLastError());
  1098. }
  1099. } // hMutex != NULL
  1100. }
  1101. }
  1102. }
  1103. return(fCopyResult);
  1104. }
  1105. }
  1106. }
  1107. if (fMakeErrorOnDumpCopy) {
  1108. fprintf(stderr, "BINPLACE : error BNP0000: File '%s' is not listed in '%s'. Copying to dump.\n", FullFileName, PlaceFileName);
  1109. return CopyTheFile(
  1110. FullFileName,
  1111. FilePart,
  1112. PutInDebug ? "Symbols" : (PutInLcDir ? BinplaceLcDir : (DumpOverride ? DumpOverride : DEFAULT_DUMP)),
  1113. NULL
  1114. );
  1115. } else {
  1116. return TRUE;
  1117. }
  1118. }
  1119. BOOL
  1120. CopyTheFile(
  1121. LPSTR SourceFileName,
  1122. LPSTR SourceFilePart,
  1123. LPSTR DestinationSubdir,
  1124. LPSTR DestinationFilePart
  1125. )
  1126. {
  1127. CHAR DestinationFile[MAX_PATH+1];
  1128. CHAR TmpDestinationFile[MAX_PATH+1];
  1129. CHAR TmpDestinationDir[MAX_PATH+1];
  1130. CHAR DestinationLcFile[MAX_PATH+1];
  1131. char Drive[_MAX_DRIVE];
  1132. char Dir[_MAX_DIR];
  1133. char Ext[_MAX_EXT];
  1134. char Name[_MAX_FNAME];
  1135. char TmpName[_MAX_FNAME];
  1136. char TmpPath[_MAX_PATH+1];
  1137. char FileSystemType[8];
  1138. char DriveRoot[4];
  1139. CHAR *TmpSymbolFilePath;
  1140. DWORD dwFileSystemFlags;
  1141. DWORD dwMaxCompLength;
  1142. CHAR ErrMsg[MAX_SYM_ERR]; // Symbol checking error message
  1143. BOOL fBinplaceLc;
  1144. ULONG SymbolFlag;
  1145. BOOL fRetail;
  1146. if ( !PlaceRootName ) {
  1147. fprintf(stderr,"BINPLACE : warning BNP0000: PlaceRoot is not specified\n");
  1148. return FALSE;
  1149. }
  1150. if (fCheckDelayload && !_stricmp(SourceFilePart, gDelayLoadModule))
  1151. {
  1152. StringCbCopy(TmpDestinationFile, sizeof(TmpDestinationFile), PlaceRootName);
  1153. StringCbCat( TmpDestinationFile, sizeof(TmpDestinationFile), "\\");
  1154. StringCbCat( TmpDestinationFile, sizeof(TmpDestinationFile), DEFAULT_DELAYLOADDIR);
  1155. StringCbCat( TmpDestinationFile, sizeof(TmpDestinationFile), "\\");
  1156. StringCbCat( TmpDestinationFile, sizeof(TmpDestinationFile), SourceFilePart);
  1157. StringCbCat( TmpDestinationFile, sizeof(TmpDestinationFile), ".ini");
  1158. if (!MakeSureDirectoryPathExists(TmpDestinationFile))
  1159. {
  1160. fprintf(stderr, "BINPLACE : error BNP0000: Unable to create directory path '%s' (%u)\n", TmpDestinationFile, GetLastError());
  1161. }
  1162. else
  1163. {
  1164. WritePrivateProfileString("Default", "DelayLoadHandler", gDelayLoadHandler, TmpDestinationFile);
  1165. StringCbCopy(TmpDestinationDir, sizeof(TmpDestinationDir), ".\\"); //default to "retail"
  1166. if ((*DestinationSubdir != '.') && (*(DestinationSubdir+1) != '\0'))
  1167. {
  1168. StringCbCopy(TmpDestinationDir,sizeof(TmpDestinationDir), DestinationSubdir);
  1169. StringCbCat( TmpDestinationDir,sizeof(TmpDestinationDir), "\\");
  1170. }
  1171. WritePrivateProfileString("Default", "DestinationDir", TmpDestinationDir, TmpDestinationFile);
  1172. }
  1173. }
  1174. //
  1175. // We also neuter SourceIsNewer on FAT partitions since they have a 2 second
  1176. // file time granularity
  1177. //
  1178. _splitpath(SourceFileName, DriveRoot, Dir, NULL, NULL);
  1179. StringCbCat(DriveRoot, sizeof(DriveRoot), "\\");
  1180. GetVolumeInformation(DriveRoot, NULL, 0, NULL, &dwMaxCompLength, &dwFileSystemFlags, FileSystemType, 7);
  1181. if (lstrcmpi(FileSystemType, "FAT") == 0 || lstrcmpi(FileSystemType, "FAT32") == 0)
  1182. fPatheticOS = TRUE;
  1183. StringCbCopy(DestinationFile, sizeof(DestinationFile), PlaceRootName);
  1184. StringCbCat( DestinationFile, sizeof(DestinationFile), "\\");
  1185. StringCbCat( DestinationFile, sizeof(DestinationFile), DestinationSubdir);
  1186. StringCbCat( DestinationFile, sizeof(DestinationFile), "\\");
  1187. StringCbCopy(TmpDestinationDir, sizeof(TmpDestinationDir), DestinationFile);
  1188. if (!MakeSureDirectoryPathExists(DestinationFile)) {
  1189. fprintf(stderr, "BINPLACE : error BNP0000: Unable to create directory path '%s' (%u)\n",
  1190. DestinationFile, GetLastError()
  1191. );
  1192. }
  1193. if (DestinationFilePart) {
  1194. StringCbCat(DestinationFile, sizeof(DestinationFile), DestinationFilePart);
  1195. } else {
  1196. StringCbCat(DestinationFile, sizeof(DestinationFile), SourceFilePart);
  1197. }
  1198. if ((fVerbose || fTestMode)) {
  1199. fprintf(stdout,"BINPLACE : warning BNP0000: place %s in %s\n",SourceFileName,DestinationFile);
  1200. }
  1201. // SymbolFlag = IGNORE_IF_SPLIT;
  1202. fRetail = (*DestinationSubdir == '.') && (*(DestinationSubdir+1) == '\0');
  1203. if ( fForcePlace||SourceIsNewer(SourceFileName,DestinationFile,fPatheticOS) ) {
  1204. fprintf(stdout, "binplace %s\n", SourceFileName);
  1205. if (!VerifyFinalImage(SourceFileName, fRetail, fVerifyLc, LcFullFileName, pVerifyLocConstraintA, &fBinplaceLc) )
  1206. return FALSE;
  1207. // Verify Symbols
  1208. if ( fSymChecking && !fSignCode) {
  1209. _splitpath(SourceFileName,Drive, Dir, Name, Ext );
  1210. StringCbCopy(TmpName, sizeof(TmpName), Name);
  1211. StringCbCat( TmpName, sizeof(TmpName), Ext);
  1212. StringCbCopy(TmpPath, sizeof(TmpPath), Drive);
  1213. StringCbCat( TmpPath, sizeof(TmpPath), Dir);
  1214. if (!CheckSymbols( SourceFileName,
  1215. TmpPath,
  1216. ExcludeFileName,
  1217. fDbgControl,
  1218. ErrMsg,
  1219. sizeof(ErrMsg)
  1220. ) ) {
  1221. fprintf(stderr,"BINPLACE : error BNP0000: %s",ErrMsg);
  1222. return FALSE;
  1223. }
  1224. }
  1225. }
  1226. // Store the destination globally so we can access it for output to the log file
  1227. StringCbCopy( gDestinationFile, sizeof(gDestinationFile), DestinationFile );
  1228. if (!fTestMode) {
  1229. //
  1230. // In Setup mode, copy the file only if it's newer than
  1231. // the one that's already there.
  1232. //
  1233. if ( fForcePlace||SourceIsNewer(SourceFileName,DestinationFile,fPatheticOS) ) {
  1234. if (fVerbose) {
  1235. fprintf(stdout,"BINPLACE : warning BNP0000: copy %s to %s\n",SourceFileName,DestinationFile);
  1236. }
  1237. } else {
  1238. return(TRUE);
  1239. }
  1240. SetFileAttributes(DestinationFile,FILE_ATTRIBUTE_NORMAL);
  1241. if (!fIgnoreHardLinks && fHardLinks) {
  1242. if ((*pCreateHardLinkA)(SourceFileName, DestinationFile, NULL)) {
  1243. if (!fKeepAttributes)
  1244. SetFileAttributes(DestinationFile,FILE_ATTRIBUTE_NORMAL);
  1245. return(TRUE);
  1246. }
  1247. }
  1248. if ( !CopyFile(SourceFileName,DestinationFile, FALSE)) {
  1249. fprintf(stderr,"BINPLACE : warning BNP0000: CopyFile(%s,%s) failed %d\n",SourceFileName,DestinationFile,GetLastError());
  1250. return FALSE;
  1251. }
  1252. if (!fKeepAttributes)
  1253. SetFileAttributes(DestinationFile,FILE_ATTRIBUTE_NORMAL);
  1254. if (!fNoClassInSymbolsDir) {
  1255. StringCbCopy(TmpDestinationDir, sizeof(TmpDestinationDir), SymbolFilePath);
  1256. if ((DestinationSubdir[0] == '.') && (DestinationSubdir[1] == '\0')) {
  1257. StringCbCat(TmpDestinationDir, sizeof(TmpDestinationDir),"\\retail");
  1258. } else {
  1259. char * pSubdir;
  1260. char * pTmp;
  1261. StringCbCat(TmpDestinationDir, sizeof(TmpDestinationDir), "\\");
  1262. pSubdir = DestinationSubdir;
  1263. if (pSubdir[0] == '.' && pSubdir[1] == '\\')
  1264. {
  1265. pSubdir += 2;
  1266. }
  1267. //
  1268. // Put the root dir only on the path
  1269. // Optionally change asms to retail.
  1270. //
  1271. pTmp = strchr(pSubdir, '\\');
  1272. if (pTmp) {
  1273. const static char asms[] = "asms\\";
  1274. if (fChangeAsmsToRetailForSymbols
  1275. && _strnicmp(pSubdir, asms, sizeof(asms) - 1) ==0) {
  1276. //
  1277. StringCbCopy(TmpDestinationFile, sizeof(TmpDestinationFile), "retail");
  1278. StringCbCat( TmpDestinationDir, sizeof(TmpDestinationDir), TmpDestinationFile);
  1279. } else {
  1280. StringCbCopy(TmpDestinationFile, sizeof(TmpDestinationFile), pSubdir);
  1281. TmpDestinationFile[pTmp - pSubdir] = '\0';
  1282. StringCbCat(TmpDestinationDir, sizeof(TmpDestinationDir), TmpDestinationFile);
  1283. }
  1284. } else {
  1285. StringCbCat(TmpDestinationDir, sizeof(TmpDestinationDir), pSubdir);
  1286. }
  1287. }
  1288. TmpSymbolFilePath = TmpDestinationDir;
  1289. } else {
  1290. TmpSymbolFilePath = SymbolFilePath;
  1291. }
  1292. if (fSplitSymbols && !fBypassSplitSymX) {
  1293. // temp var for getting PDB path from SplitSymbolsX()
  1294. CHAR TempFullPublicPdbPath[MAX_PATH]="";
  1295. LPSTR* tmp = NULL;
  1296. _splitpath(SourceFileName, Drive, Dir, NULL, Ext);
  1297. _makepath(DebugFilePath, Drive, Dir, NULL, NULL);
  1298. SplitFlags |= SPLITSYM_SYMBOLPATH_IS_SRC;
  1299. if ( SplitSymbolsX( DestinationFile, TmpSymbolFilePath, (PCHAR) DebugFilePath, sizeof(DebugFilePath),
  1300. SplitFlags, szRSDSDllToLoad, TempFullPublicPdbPath, sizeof(TempFullPublicPdbPath) )) {
  1301. if (fVerbose)
  1302. fprintf( stdout, "BINPLACE : warning BNP0000: Symbols stripped from %s into %s\n", DestinationFile, DebugFilePath);
  1303. if (fLogPdbPaths) {
  1304. if ( GetFullPathName(TempFullPublicPdbPath, MAX_PATH+1, gPublicPdbFullPath, tmp) > (MAX_PATH+1) ) {
  1305. gPublicPdbFullPath[0] = '\0';
  1306. }
  1307. }
  1308. } else {
  1309. if (fVerbose)
  1310. fprintf( stdout, "BINPLACE : warning BNP0000: No symbols to strip from %s\n", DestinationFile);
  1311. if ( ! ConcatPaths(DebugFilePath, sizeof(DebugFilePath), PlaceRootName, TmpSymbolFilePath, &Ext[1]) ) {
  1312. fprintf(stderr, "BINPLACE : error BNP1532: Unable to create public symbol file path.\n");
  1313. return(FALSE);
  1314. } else {
  1315. if (fVerbose) {
  1316. fprintf( stdout, "BINPLACE : warning BNP1536: Public symbols being copied to %s.\n", DebugFilePath);
  1317. }
  1318. }
  1319. BinplaceCopyPdb(DebugFilePath, SourceFileName, TRUE, SplitFlags & SPLITSYM_REMOVE_PRIVATE);
  1320. }
  1321. if ((SplitFlags & SPLITSYM_REMOVE_PRIVATE) && (PrivateSymbolFilePath != NULL)) {
  1322. CHAR Dir1[_MAX_PATH];
  1323. CHAR Dir2[_MAX_PATH];
  1324. _splitpath(DebugFilePath, Drive, Dir, NULL, NULL);
  1325. _makepath(Dir1, Drive, Dir, NULL, NULL);
  1326. StringCbCopy(Dir2, sizeof(Dir2), PrivateSymbolFilePath);
  1327. StringCbCat( Dir2, sizeof(Dir2), Dir1+strlen(SymbolFilePath));
  1328. MakeSureDirectoryPathExists(Dir2);
  1329. BinplaceCopyPdb(Dir2, SourceFileName, TRUE, FALSE);
  1330. }
  1331. } else {
  1332. BinplaceCopyPdb(DestinationFile, SourceFileName, FALSE, fSplitSymbols ? (SplitFlags & SPLITSYM_REMOVE_PRIVATE) : FALSE);
  1333. }
  1334. //
  1335. // trace formatting
  1336. //
  1337. if (fWppFmt) {
  1338. CHAR PdbName[MAX_PATH+1];
  1339. DWORD PdbSig;
  1340. if ( BinplaceGetSourcePdbName(SourceFileName, sizeof(PdbName), PdbName, &PdbSig) ) {
  1341. if (strcmp(PdbName,LastPdbName) != 0) { // Have we just processed this PDB?
  1342. if (fVerbose) {
  1343. fprintf( stdout, "BINPLACE : warning BNP0000: Trace Formats being built from %s\n", PdbName );
  1344. }
  1345. if (TraceFormatFilePath[0] == '\0') {
  1346. if (PrivateSymbolFilePath != NULL) {
  1347. StringCbPrintfA(TraceFormatFilePath,sizeof(TraceFormatFilePath),"%s\\%s",PrivateSymbolFilePath,TraceDir);
  1348. } else {
  1349. strncpy(TraceFormatFilePath, TraceDir, MAX_PATH) ;
  1350. }
  1351. if (fVerbose) {
  1352. fprintf( stdout, "BINPLACE : warning BNP0000: Trace Formats file path set to %s\n", TraceFormatFilePath );
  1353. }
  1354. }
  1355. BinplaceWppFmt(PdbName, TraceFormatFilePath, szRSDSDllToLoad, fVerbose);
  1356. // because files are frequently copied to multiple places, the PDB is also placed
  1357. // several times, there is no point in us processing it more than once.
  1358. strncpy(LastPdbName,PdbName,MAX_PATH);
  1359. } else {
  1360. if (fVerbose) {
  1361. fprintf( stdout, "BINPLACE : warning BNP0000: Trace Formats skipping %s (same as last)\n", PdbName );
  1362. }
  1363. }
  1364. }
  1365. }
  1366. StripCVSymbolPath(DestinationFile);
  1367. if (fPlaceWin95SymFile) {
  1368. char DestSymPath[_MAX_PATH];
  1369. char DestSymDir[_MAX_PATH];
  1370. char SrcSymPath[_MAX_PATH];
  1371. _splitpath(CurrentImageName, Drive, Dir, Name, Ext);
  1372. _makepath(SrcSymPath, Drive, Dir, Name, ".sym");
  1373. if (!_access(SrcSymPath, 0)) {
  1374. if (fSplitSymbols) {
  1375. StringCbCopy(DestSymPath, sizeof(DestSymPath), TmpSymbolFilePath);
  1376. StringCbCat( DestSymPath, sizeof(DestSymPath), "\\");
  1377. StringCbCat( DestSymPath, sizeof(DestSymPath), Ext[0] == '.' ? &Ext[1] : Ext);
  1378. StringCbCat( DestSymPath, sizeof(DestSymPath), "\\");
  1379. StringCbCat( DestSymPath, sizeof(DestSymPath), Name);
  1380. StringCbCat( DestSymPath, sizeof(DestSymPath), ".sym");
  1381. } else {
  1382. _splitpath(DestinationFile, Drive, Dir, NULL, NULL);
  1383. _makepath(DestSymPath, Drive, Dir, Name, ".sym");
  1384. }
  1385. SetFileAttributes(DestSymPath, FILE_ATTRIBUTE_NORMAL);
  1386. if ( fForcePlace||SourceIsNewer(SrcSymPath, SourceFileName,fPatheticOS) ) {
  1387. // Only binplace the .sym file if it was built AFTER the image itself.
  1388. // Make sure to create the destination path in case it is not there already.
  1389. StringCbCopy(DestSymDir, sizeof(DestSymDir), TmpSymbolFilePath);
  1390. StringCbCat( DestSymDir, sizeof(DestSymDir), "\\");
  1391. StringCbCat( DestSymDir, sizeof(DestSymDir), Ext[0] == '.' ? &Ext[1] : Ext);
  1392. StringCbCat( DestSymDir, sizeof(DestSymDir), "\\");
  1393. MakeSureDirectoryPathExists(DestSymDir);
  1394. if (!CopyFile(SrcSymPath, DestSymPath, FALSE)) {
  1395. fprintf(stderr,"BINPLACE : warning BNP0000: CopyFile(%s,%s) failed %d\n", SrcSymPath, DestSymPath ,GetLastError());
  1396. }
  1397. }
  1398. if (!fKeepAttributes)
  1399. SetFileAttributes(DestinationFile,FILE_ATTRIBUTE_NORMAL);
  1400. } else {
  1401. if (fVerbose) {
  1402. fprintf( stdout, "BINPLACE : warning BNP0000: Unable to locate \"%s\" for \"%s\"\n", SrcSymPath, CurrentImageName );
  1403. }
  1404. }
  1405. }
  1406. if (fDigitalSign) {
  1407. SignWithIDWKey( DestinationFile, fVerbose );
  1408. }
  1409. if (fBinplaceLc) {
  1410. StringCbCopy(DestinationLcFile, sizeof(DestinationLcFile), PlaceRootName);
  1411. StringCbCat( DestinationLcFile, sizeof(DestinationLcFile), "\\");
  1412. StringCbCat( DestinationLcFile, sizeof(DestinationLcFile), BinplaceLcDir);
  1413. StringCbCat( DestinationLcFile, sizeof(DestinationLcFile), "\\");
  1414. StringCbCat( DestinationLcFile, sizeof(DestinationLcFile), DestinationSubdir);
  1415. StringCbCat( DestinationLcFile, sizeof(DestinationLcFile), "\\");
  1416. if (!MakeSureDirectoryPathExists(DestinationLcFile)) {
  1417. fprintf(stderr, "BINPLACE : error BNP0000: Unable to create directory path '%s' (%u)\n",
  1418. DestinationLcFile, GetLastError()
  1419. );
  1420. }
  1421. StringCbCat(DestinationLcFile, sizeof(DestinationLcFile), LcFilePart);
  1422. if (!CopyFile(LcFullFileName, DestinationLcFile, FALSE)) {
  1423. fprintf(stderr,"BINPLACE : warning BNP0000: CopyFile(%s,%s) failed %d\n",
  1424. LcFullFileName,DestinationLcFile,GetLastError());
  1425. }
  1426. }
  1427. }
  1428. return TRUE;
  1429. }
  1430. BOOL
  1431. BinplaceCopyPdb (
  1432. LPSTR DestinationFile,
  1433. LPSTR SourceFileName,
  1434. BOOL CopyFromSourceOnly,
  1435. BOOL StripPrivate
  1436. )
  1437. {
  1438. LOADED_IMAGE LoadedImage;
  1439. DWORD DirCnt;
  1440. IMAGE_DEBUG_DIRECTORY UNALIGNED *DebugDirs, *CvDebugDir;
  1441. if (MapAndLoad(
  1442. CopyFromSourceOnly ? SourceFileName : DestinationFile,
  1443. NULL,
  1444. &LoadedImage,
  1445. FALSE,
  1446. CopyFromSourceOnly ? TRUE : FALSE) == FALSE) {
  1447. return (FALSE);
  1448. }
  1449. DebugDirs = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData(
  1450. LoadedImage.MappedAddress,
  1451. FALSE,
  1452. IMAGE_DIRECTORY_ENTRY_DEBUG,
  1453. &DirCnt
  1454. );
  1455. if (!DebugDirectoryIsUseful(DebugDirs, DirCnt)) {
  1456. UnMapAndLoad(&LoadedImage);
  1457. return(FALSE);
  1458. }
  1459. DirCnt /= sizeof(IMAGE_DEBUG_DIRECTORY);
  1460. CvDebugDir = NULL;
  1461. while (DirCnt) {
  1462. DirCnt--;
  1463. if (DebugDirs[DirCnt].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
  1464. CvDebugDir = &DebugDirs[DirCnt];
  1465. break;
  1466. }
  1467. }
  1468. if (!CvDebugDir) {
  1469. // Didn't find any CV debug dir. Bail.
  1470. UnMapAndLoad(&LoadedImage);
  1471. return(FALSE);
  1472. }
  1473. if (CvDebugDir->PointerToRawData != 0) {
  1474. PCVDD pDebugDir;
  1475. ULONG mysize;
  1476. pDebugDir = (PCVDD) (CvDebugDir->PointerToRawData + (PCHAR)LoadedImage.MappedAddress);
  1477. if (pDebugDir->dwSig == '01BN' ) {
  1478. mysize=sizeof(NB10IH);
  1479. } else {
  1480. mysize=sizeof(RSDSIH);
  1481. }
  1482. if (pDebugDir->dwSig == '01BN' || pDebugDir->dwSig == 'SDSR' ) {
  1483. // Got a PDB. The name immediately follows the signature.
  1484. LPSTR szMyDllToLoad;
  1485. CHAR PdbName[sizeof(((PRSDSI)(0))->szPdb)];
  1486. CHAR NewPdbName[sizeof(((PRSDSI)(0))->szPdb)];
  1487. CHAR Drive[_MAX_DRIVE];
  1488. CHAR Dir[_MAX_DIR];
  1489. CHAR Filename[_MAX_FNAME];
  1490. CHAR FileExt[_MAX_EXT];
  1491. if (pDebugDir->dwSig == '01BN') {
  1492. szMyDllToLoad=NULL;
  1493. } else {
  1494. szMyDllToLoad=szRSDSDllToLoad;
  1495. }
  1496. ZeroMemory(PdbName, sizeof(PdbName));
  1497. memcpy(PdbName, ((PCHAR)pDebugDir) + mysize, __min(CvDebugDir->SizeOfData - mysize, sizeof(PdbName)));
  1498. _splitpath(PdbName, NULL, NULL, Filename, FileExt);
  1499. // Calculate the destination name
  1500. _splitpath(DestinationFile, Drive, Dir, NULL, NULL);
  1501. _makepath(NewPdbName, Drive, Dir, Filename, FileExt);
  1502. // Then the source name. First we try in the same dir as the image itself
  1503. _splitpath(SourceFileName, Drive, Dir, NULL, NULL);
  1504. _makepath(PdbName, Drive, Dir, Filename, FileExt);
  1505. if ((fVerbose || fTestMode)) {
  1506. fprintf(stdout,"BINPLACE : warning BNP0000: place %s in %s\n", PdbName, NewPdbName);
  1507. }
  1508. if (!MakeSureDirectoryPathExists(NewPdbName)) {
  1509. fprintf(stderr, "BINPLACE : error BNP0000: Unable to create directory path '%s' (%u)\n",
  1510. NewPdbName, GetLastError());
  1511. }
  1512. SetFileAttributes(NewPdbName,FILE_ATTRIBUTE_NORMAL);
  1513. if (fLogPdbPaths) {
  1514. LPTSTR *tmp=NULL;
  1515. // when stripping privates, we get the public pdb path, otherwise we get the private pdb path
  1516. if ( StripPrivate ) {
  1517. // use GetFullPathName to normalize path
  1518. if ( GetFullPathName(NewPdbName, MAX_PATH+1, gPublicPdbFullPath, tmp) > (MAX_PATH+1) ) {
  1519. gPublicPdbFullPath[0] = '\0';
  1520. fprintf(stderr,"BINPLACE : warning BNP1697: Unable to log PDB public path\n");
  1521. }
  1522. } else {
  1523. // use GetFullPathName to normalize path
  1524. if ( GetFullPathName(NewPdbName, MAX_PATH+1, gPrivatePdbFullPath, tmp) > (MAX_PATH+1) ) {
  1525. gPrivatePdbFullPath[0] = '\0';
  1526. fprintf(stderr,"BINPLACE : warning BNP1691: Unable to log PDB private path\n");
  1527. }
  1528. }
  1529. }
  1530. if ( !CopyPdbX(PdbName, NewPdbName, StripPrivate, szMyDllToLoad)) {
  1531. if ((fVerbose || fTestMode)) {
  1532. fprintf(stderr,"BINPLACE : warning BNP0000: Unable to copy (%s,%s) %d\n", PdbName, NewPdbName, GetLastError());
  1533. }
  1534. // The file is not in the same dir as the image - try the path listed in the image
  1535. ZeroMemory(PdbName, sizeof(PdbName));
  1536. memcpy(PdbName, ((PCHAR)pDebugDir) + mysize, __min(CvDebugDir->SizeOfData - mysize, sizeof(PdbName)));
  1537. if ((fVerbose || fTestMode)) {
  1538. fprintf(stdout,"BINPLACE : warning BNP0000: place %s in %s\n", PdbName, NewPdbName);
  1539. }
  1540. if ( !CopyPdbX(PdbName, NewPdbName, StripPrivate, szMyDllToLoad)) {
  1541. if (fLogPdbPaths) {
  1542. if ( StripPrivate ) {
  1543. gPublicPdbFullPath[0] = '\0';
  1544. fprintf(stderr,"BINPLACE : warning BNP1697: Unable to log PDB public path (%s)\n", NewPdbName);
  1545. } else {
  1546. gPrivatePdbFullPath[0] = '\0';
  1547. fprintf(stderr,"BINPLACE : warning BNP1697: Unable to log PDB private path (%s)\n", NewPdbName);
  1548. }
  1549. }
  1550. // fprintf(stderr,"BINPLACE : warning BNP0000: CopyPdb(%s,%s) failed %d\n", PdbName, NewPdbName, GetLastError());
  1551. }
  1552. }
  1553. if (!fKeepAttributes)
  1554. SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
  1555. if (fSrcControl && !StripPrivate) {
  1556. CHAR CvdumpName[sizeof(((PRSDSI)(0))->szPdb)]; // [_MAX_PATH + _MAX_FNAME];
  1557. UINT i;
  1558. LONG pos;
  1559. CHAR buf[_MAX_PATH*3];
  1560. // Find the start of "symbols.pri" in NewPdbName
  1561. pos=-1;
  1562. i=0;
  1563. while ( (i < strlen(NewPdbName) - strlen("symbols.pri")) && pos== -1) {
  1564. if (_strnicmp( NewPdbName+i, "symbols.pri", strlen("symbols.pri") ) == 0 ) {
  1565. pos=i;
  1566. } else {
  1567. i++;
  1568. }
  1569. }
  1570. if ( pos >= 0 ) {
  1571. StringCbCopy(CvdumpName, sizeof(CvdumpName), NewPdbName);
  1572. CvdumpName[i]='\0';
  1573. StringCbCat(CvdumpName, sizeof(CvdumpName), "cvdump.pri" );
  1574. StringCbCat(CvdumpName, sizeof(CvdumpName), NewPdbName + pos + strlen("symbols.pri") );
  1575. StringCbCat(CvdumpName, sizeof(CvdumpName), ".dmp");
  1576. // Get the Directory name and create it
  1577. if ( MakeSureDirectoryPathExists(CvdumpName) ) {
  1578. StringCbPrintfA(buf, sizeof(buf), "cvdump -sf %s > %s", NewPdbName, CvdumpName);
  1579. // Spawn off cvdump.exe - this is a security risk since we don't specifically specify the path
  1580. // to cvdump.exe. However, we can't guarentee that it exists nor that
  1581. // if we find it dynamically that the correct one will be used so I'm not
  1582. // certain that we can do this any differently.
  1583. system(buf);
  1584. } else {
  1585. fprintf( stdout, "BINPLACE : error BNP0000: Cannot create directory for the file %s\n", CvdumpName);
  1586. }
  1587. }
  1588. }
  1589. }
  1590. UnMapAndLoad(&LoadedImage);
  1591. return(TRUE);
  1592. }
  1593. UnMapAndLoad(&LoadedImage);
  1594. return(FALSE);
  1595. }
  1596. //
  1597. // Finds the name of the source PDB using the CV data from the source binary. Returns the name and the
  1598. // PDB Sig.
  1599. //
  1600. BOOL BinplaceGetSourcePdbName(LPTSTR SourceFileName, DWORD BufferSize, CHAR* SourcePdbName, DWORD* PdbSig) {
  1601. BOOL Return = FALSE;
  1602. LOADED_IMAGE LoadedImage;
  1603. DWORD DirCnt;
  1604. IMAGE_DEBUG_DIRECTORY UNALIGNED *DebugDirs,
  1605. *CvDebugDir;
  1606. if (MapAndLoad(SourceFileName,
  1607. NULL,
  1608. &LoadedImage,
  1609. FALSE,
  1610. TRUE) == FALSE) {
  1611. return (FALSE);
  1612. }
  1613. DebugDirs = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData(LoadedImage.MappedAddress,
  1614. FALSE,
  1615. IMAGE_DIRECTORY_ENTRY_DEBUG,
  1616. &DirCnt);
  1617. if (!DebugDirectoryIsUseful(DebugDirs, DirCnt)) {
  1618. UnMapAndLoad(&LoadedImage);
  1619. return(FALSE);
  1620. }
  1621. DirCnt /= sizeof(IMAGE_DEBUG_DIRECTORY);
  1622. CvDebugDir = NULL;
  1623. while (DirCnt) {
  1624. DirCnt--;
  1625. if (DebugDirs[DirCnt].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
  1626. CvDebugDir = &DebugDirs[DirCnt];
  1627. break;
  1628. }
  1629. }
  1630. if (!CvDebugDir) {
  1631. // Didn't find any CV debug dir. Bail.
  1632. UnMapAndLoad(&LoadedImage);
  1633. return(FALSE);
  1634. }
  1635. if (CvDebugDir->PointerToRawData != 0) {
  1636. PCVDD pDebugDir;
  1637. ULONG mysize;
  1638. pDebugDir = (PCVDD) (CvDebugDir->PointerToRawData + (PCHAR)LoadedImage.MappedAddress);
  1639. *PdbSig = pDebugDir->dwSig;
  1640. if (pDebugDir->dwSig == '01BN' ) {
  1641. mysize=sizeof(NB10IH);
  1642. } else {
  1643. mysize=sizeof(RSDSIH);
  1644. }
  1645. if (pDebugDir->dwSig == '01BN' || pDebugDir->dwSig == 'SDSR' ) {
  1646. // Got a PDB. The name immediately follows the signature.
  1647. LPSTR szMyDllToLoad;
  1648. CHAR PdbName[sizeof(((PRSDSI)(0))->szPdb)];
  1649. CHAR NewPdbName[sizeof(((PRSDSI)(0))->szPdb)];
  1650. CHAR Drive[_MAX_DRIVE];
  1651. CHAR Dir[_MAX_DIR];
  1652. CHAR Filename[_MAX_FNAME];
  1653. CHAR FileExt[_MAX_EXT];
  1654. ZeroMemory(PdbName, sizeof(PdbName));
  1655. StringCbCopy(PdbName, sizeof(PdbName), ((PCHAR)pDebugDir) + mysize);
  1656. _splitpath(PdbName, NULL, NULL, Filename, FileExt);
  1657. // Then the source name. First we try in the same dir as the image itself
  1658. _splitpath(SourceFileName, Drive, Dir, NULL, NULL);
  1659. _makepath(SourcePdbName, Drive, Dir, Filename, FileExt);
  1660. //
  1661. // Handle the case where the PDB doesn't exist in the given location
  1662. // by checking for it in the same directory as the binary!
  1663. //
  1664. // make sure the file exists and is readable
  1665. if ( _access(SourcePdbName, 4) != 0 ) {
  1666. // The file is not in the same dir as the image - try the path listed in the image
  1667. memcpy(SourcePdbName, ((PCHAR)pDebugDir) + mysize, __min(CvDebugDir->SizeOfData - mysize, BufferSize));
  1668. // make sure the file exists and is readable
  1669. if ( _access(SourcePdbName, 4) == 0 ) {
  1670. Return = TRUE;
  1671. }
  1672. } else {
  1673. Return = TRUE;
  1674. }
  1675. }
  1676. UnMapAndLoad(&LoadedImage);
  1677. return(TRUE);
  1678. }
  1679. UnMapAndLoad(&LoadedImage);
  1680. return(FALSE);
  1681. }
  1682. // shared globals for InitMessageBufferWithCwd(), GetAndLogNextArg() and PrintMessageLogBuffer()
  1683. static CHAR * MessageLogBuffer= NULL;
  1684. static BOOL MessageLogError = FALSE;
  1685. // puts CWD into MessageLogBuffer
  1686. BOOL InitMessageBufferWithCwd(void) {
  1687. BOOL fRetVal = FALSE;
  1688. if ( GetCurrentDirectory(_msize(MessageLogBuffer)/sizeof(TCHAR), MessageLogBuffer) == 0 ) {
  1689. // use GetLastError() to find the specifics- all I care about here is
  1690. // whether we succeeded or not.
  1691. fRetVal = FALSE;
  1692. } else {
  1693. if (StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), " ") != S_OK) {
  1694. fRetVal = FALSE;
  1695. } else {
  1696. fRetVal = TRUE;
  1697. }
  1698. }
  1699. return(fRetVal);
  1700. }
  1701. // Calls GetNextArg and logs the result
  1702. DWORD GetAndLogNextArg(OUT TCHAR* Buffer, IN DWORD BufferSize, OPTIONAL OUT DWORD* RequiredSize) {
  1703. DWORD TempValue = GetNextArg(Buffer, BufferSize, RequiredSize);
  1704. CHAR* TempBuffer;
  1705. if (MessageLogBuffer == NULL) {
  1706. MessageLogBuffer = (CHAR*)malloc(sizeof(CHAR)*1024); // initial size
  1707. // make sure we have memory
  1708. if ( MessageLogBuffer == NULL ) {
  1709. MessageLogError = TRUE;
  1710. fprintf(stderr,"BINPLACE : warning BNP1771: Unable log command line.");
  1711. // stick CWD into buffer
  1712. } else if ( ! InitMessageBufferWithCwd() ) {
  1713. MessageLogError = TRUE;
  1714. fprintf(stderr,"BINPLACE : warning BNP1771: Unable log command line.");
  1715. // add this arg to the buffer
  1716. } else if ( StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), Buffer) != S_OK||
  1717. StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), " ") != S_OK) {
  1718. MessageLogError = TRUE;
  1719. fprintf(stderr,"BINPLACE : warning BNP1771: Unable log command line.");
  1720. }
  1721. } else {
  1722. if (_msize(MessageLogBuffer) < strlen(MessageLogBuffer) + strlen(Buffer) + 2) {
  1723. TempBuffer = (CHAR*)realloc(MessageLogBuffer, _msize(MessageLogBuffer) + 1024);
  1724. if (TempBuffer == NULL) {
  1725. MessageLogError = TRUE;
  1726. fprintf(stderr,"BINPLACE : warning BNP1779: Unable log command line.");
  1727. } else {
  1728. MessageLogBuffer = TempBuffer;
  1729. if (StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), Buffer) != S_OK) {
  1730. MessageLogError = TRUE;
  1731. fprintf(stderr,"BINPLACE : warning BNP1783: Unable log command line.");
  1732. }
  1733. if (StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), " ") != S_OK) {
  1734. MessageLogError = TRUE;
  1735. fprintf(stderr,"BINPLACE : warning BNP1783: Unable log command line.");
  1736. }
  1737. }
  1738. } else {
  1739. if (StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), Buffer) != S_OK) {
  1740. MessageLogError = TRUE;
  1741. fprintf(stderr,"BINPLACE : warning BNP1783: Unable log command line.");
  1742. }
  1743. if (StringCbCat(MessageLogBuffer, _msize(MessageLogBuffer), " ") != S_OK) {
  1744. MessageLogError = TRUE;
  1745. fprintf(stderr,"BINPLACE : warning BNP1783: Unable log command line.");
  1746. }
  1747. }
  1748. }
  1749. return(TempValue);
  1750. }
  1751. // writes LogBuffer to supplied handle
  1752. BOOL PrintMessageLogBuffer(FILE* fLogHandle) {
  1753. BOOL bRetVal = TRUE;
  1754. if (fLogHandle != NULL) {
  1755. if (MessageLogError) {
  1756. // ';' denotes the beginning of a comment in the binplace message log
  1757. // write what we can of the command line and note that it might not be valid
  1758. // also, write the line as a comment to avoid accicental execution of it.
  1759. fprintf(fLogHandle, "; ERROR: Possible bad command line follows\n");
  1760. fprintf(fLogHandle, "; %s\n", MessageLogBuffer);
  1761. } else {
  1762. fprintf(fLogHandle, "%s\n", MessageLogBuffer);
  1763. }
  1764. }
  1765. return(bRetVal);
  1766. }
  1767. BOOL FreeMessageLogBuffer(void) {
  1768. if (MessageLogBuffer != NULL) {
  1769. free(MessageLogBuffer);
  1770. MessageLogBuffer = NULL;
  1771. }
  1772. return(TRUE);
  1773. }
  1774. ///////////////////////////////////////////////////////////////////////////////
  1775. //
  1776. // Local replacement for GetFullPathName that correctly handles lpFileName when
  1777. // it begins with '\'
  1778. //
  1779. DWORD PrivateGetFullPathName(LPCTSTR lpFilename, DWORD nBufferLength, LPTSTR lpBuffer, LPTSTR *lpFilePart) {
  1780. DWORD Return = 0;
  1781. CHAR* ch;
  1782. //
  1783. // GetFullPath flounders when referring to the root of the drive, so use
  1784. // a private version that handles it
  1785. //
  1786. if ( lpFilename[0] == '\\' ) {
  1787. // handle network paths
  1788. if ( lpFilename[1] == '\\' ) {
  1789. if ( StringCchCopy(lpBuffer, nBufferLength, lpFilename)!=S_OK ) {
  1790. Return = 0;
  1791. } else {
  1792. // fill in the return data
  1793. ch = strrchr(lpBuffer, '\\');
  1794. ch++;
  1795. lpFilePart = (LPTSTR*)ch;
  1796. Return = strlen(lpBuffer);
  1797. }
  1798. } else {
  1799. Return = GetCurrentDirectory(nBufferLength, lpBuffer);
  1800. // truncate everything after drive name
  1801. if ( (Return!=0) && (Return <= MAX_PATH+1)) {
  1802. ch = strchr(lpBuffer, '\\');
  1803. if (ch!=NULL) {
  1804. *ch = '\0';
  1805. }
  1806. // push in the filename
  1807. if ( StringCchCat(lpBuffer, nBufferLength, lpFilename)!=S_OK ) {
  1808. Return = 0;
  1809. } else {
  1810. // fill in the return data
  1811. ch = strrchr(lpBuffer, '\\');
  1812. ch++;
  1813. lpFilePart = (LPTSTR*)ch;
  1814. Return = strlen(lpBuffer);
  1815. }
  1816. } else {
  1817. // return the needed size
  1818. }
  1819. }
  1820. } else {
  1821. //
  1822. // Not refering to drive root, just call the API
  1823. //
  1824. Return = GetFullPathName(lpFilename, nBufferLength, lpBuffer, lpFilePart);
  1825. }
  1826. return(Return);
  1827. }
  1828. //////////////////////////////////////////////////////////////////////////////////////////////
  1829. // concat 3 paths together handling the case where the second may be relative to the first
  1830. // or may be absolute
  1831. BOOL ConcatPaths( LPTSTR pszDest, size_t cbDest, LPCTSTR Root, LPCTSTR Symbols, LPCTSTR Ext) {
  1832. CHAR* TempPath = malloc(sizeof(TCHAR) * cbDest);
  1833. LPTSTR Scratch;
  1834. if (TempPath == NULL) {
  1835. return(FALSE);
  1836. }
  1837. if (Symbols[1] == ':') { // symbols contains a drive spec
  1838. if ( StringCbCopy(TempPath, cbDest, Symbols) != S_OK ) {
  1839. free(TempPath);
  1840. return(FALSE);
  1841. }
  1842. } else if (Symbols[0] == '\\') { // symbols contains a root path or UNC path
  1843. if ( Symbols[1] == '\\' ) { // UNC path
  1844. if ( StringCbCopy(TempPath, cbDest, Symbols) != S_OK ) {
  1845. free(TempPath);
  1846. return(FALSE);
  1847. }
  1848. } else { // path from drive root
  1849. CHAR drive[_MAX_DRIVE];
  1850. CHAR dir[ _MAX_DIR];
  1851. CHAR file[ _MAX_FNAME];
  1852. CHAR ext[ _MAX_EXT];
  1853. _splitpath(Root, drive, dir, file, ext);
  1854. if ( StringCbCopy(TempPath, cbDest, drive) != S_OK ) {
  1855. free(TempPath);
  1856. return(FALSE);
  1857. }
  1858. if ( StringCbCat(TempPath, cbDest, Symbols) != S_OK ) {
  1859. free(TempPath);
  1860. return(FALSE);
  1861. }
  1862. }
  1863. } else {
  1864. if ( StringCbCopy(TempPath, cbDest, Root) != S_OK ) {
  1865. free(TempPath);
  1866. return(FALSE);
  1867. }
  1868. if ( TempPath[strlen(TempPath)] != '\\' ) {
  1869. if ( StringCbCat(TempPath, cbDest, "\\") != S_OK ) {
  1870. free(TempPath);
  1871. return(FALSE);
  1872. }
  1873. }
  1874. if ( StringCbCat(TempPath, cbDest, Symbols) != S_OK ) {
  1875. free(TempPath);
  1876. return(FALSE);
  1877. }
  1878. }
  1879. if ( TempPath[strlen(TempPath)] != '\\' && Ext[0] != '\\' ) {
  1880. if ( StringCbCat(TempPath, cbDest, "\\") != S_OK ) {
  1881. free(TempPath);
  1882. return(FALSE);
  1883. }
  1884. }
  1885. if ( StringCbCat(TempPath, cbDest, Ext) != S_OK ) {
  1886. free(TempPath);
  1887. return(FALSE);
  1888. }
  1889. // final string needs to end in '\\'
  1890. if ( StringCbCat(TempPath, cbDest, "\\") != S_OK ) {
  1891. free(TempPath);
  1892. return(FALSE);
  1893. }
  1894. // return size doesn't include final \0, so don't use '<='
  1895. if ( PrivateGetFullPathName(TempPath, cbDest, pszDest, &Scratch) < cbDest ) {
  1896. free(TempPath);
  1897. return(TRUE);
  1898. } else {
  1899. free(TempPath);
  1900. return(FALSE);
  1901. }
  1902. }