Source code of Windows XP (NT5)
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.

835 lines
22 KiB

  1. #include "headers.hxx"
  2. #include "repair.hpp"
  3. #include "CSVDSReader.hpp"
  4. #include "resource.h"
  5. Repair::Repair
  6. (
  7. const CSVDSReader& csvReader409_,
  8. const CSVDSReader& csvReaderIntl_,
  9. const String& domain_,
  10. const String& rootContainerDn_,
  11. AnalisysResults& res,
  12. const String& ldiffName_,
  13. const String& csvName_,
  14. const String& saveName_,
  15. const String& logPath_,
  16. void *caleeStruct_/*=NULL*/,
  17. progressFunction stepIt_/*=NULL*/,
  18. progressFunction totalSteps_/*=NULL*/
  19. )
  20. :
  21. results(res),
  22. domain(domain_),
  23. rootContainerDn(rootContainerDn_),
  24. csvReader409(csvReader409_),
  25. csvReaderIntl(csvReaderIntl_),
  26. ldiffName(ldiffName_),
  27. csvName(csvName_),
  28. saveName(saveName_),
  29. logPath(logPath_),
  30. caleeStruct(caleeStruct_),
  31. stepIt(stepIt_),
  32. totalSteps(totalSteps_)
  33. {
  34. LOG_CTOR(Repair);
  35. ASSERT(!domain.empty());
  36. ASSERT(!rootContainerDn.empty());
  37. ASSERT(!ldiffName.empty());
  38. ASSERT(!csvName.empty());
  39. ASSERT(!saveName.empty());
  40. ASSERT(!logPath.empty());
  41. };
  42. void Repair::setProgress()
  43. {
  44. // We know the numbers bellow will fit in a long
  45. // and we want IA64 to build
  46. csvActions = static_cast<long>
  47. (
  48. results.createContainers.size() +
  49. results.createW2KObjects.size() +
  50. results.createXPObjects.size()
  51. );
  52. ldiffActions = static_cast<long>
  53. (
  54. results.objectActions.size() +
  55. results.extraneousValues.size()
  56. );
  57. // We have three main tasks:
  58. // 1) building the csv and ldif files to make the changes
  59. // (buildCsv, buildChangeLdif)
  60. // 2) saving the ldif files with objects that will change
  61. // (buildSaveLdif)
  62. // 3) running the csv and ldif files that will actually make
  63. // the changes
  64. // (runCsvOrLdif for the buildCsv and buildChangeLdif files)
  65. // For simplification, The two first tasks will be half of
  66. // the total work and the the last will be the other half.
  67. //
  68. // For task 1, each csv action takes 10 times an ldiff action.
  69. //
  70. // Each task 2 action is an ldif export that will be supposed
  71. // to take 5 times more than an ldif import, since it has to
  72. // call ldiffde to get each object.
  73. //
  74. // The total progress for 1) is
  75. // t1=csvActions*10 + ldiffActions
  76. // The progress for 2) is t2=5*ldiffActions
  77. // The progress for 3) is a proportional division of
  78. // t1+t2 between csvActions and ldiffActions that will add
  79. // up to t1
  80. // t3 = (t1+t2)*csvActions/(csvactions+ldiffActions) +
  81. // (t1+t2)*ldiffActions/(csvactions+ldiffActions)
  82. if(csvActions + ldiffActions == 0)
  83. {
  84. // We don't want to update the page if there are no
  85. // actions
  86. totalSteps=NULL;
  87. stepIt=NULL;
  88. }
  89. else
  90. {
  91. csvBuildStep=10;
  92. ldiffBuildStep=1;
  93. ldiffSaveStep=10;
  94. long totalProgress = csvBuildStep * csvActions +
  95. ldiffBuildStep * ldiffActions +
  96. ldiffSaveStep * ldiffActions;
  97. // totalProgress is accounting for task 1 and 2
  98. csvRunStep = totalProgress * csvActions /
  99. (csvActions+ldiffActions);
  100. ldiffRunStep = totalProgress - csvRunStep;
  101. // now we compute the total time
  102. totalProgress*=2;
  103. if(totalSteps!=NULL)
  104. {
  105. totalSteps(totalProgress,caleeStruct);
  106. }
  107. }
  108. }
  109. HRESULT
  110. Repair::run()
  111. {
  112. LOG_FUNCTION(Repair::run);
  113. setProgress();
  114. HRESULT hr=S_OK;
  115. do
  116. {
  117. // First we build the csv. If we can't build it
  118. // we don't want to run the LDIF and delete
  119. // the recereate objects
  120. if (csvActions != 0)
  121. {
  122. hr=buildCsv();
  123. BREAK_ON_FAILED_HRESULT(hr);
  124. }
  125. // Now we save the current objects and then
  126. // create and run the LDIF
  127. if ( ldiffActions !=0 )
  128. {
  129. // If we can't save we definatelly don't
  130. // want to change anything
  131. hr=buildSaveLdif();
  132. BREAK_ON_FAILED_HRESULT(hr);
  133. // buildChangeLdif wil build the Ldif that
  134. // will change the objects saved im
  135. // buildSaveLdif
  136. hr=buildChangeLdif();
  137. BREAK_ON_FAILED_HRESULT(hr);
  138. GetWorkFileName(
  139. String::load(IDS_FILE_NAME_LDIF_LOG),
  140. L"txt",
  141. ldifLog
  142. );
  143. // runs the Ldif built in buildChangeLdif
  144. hr=runCsvOrLdif(LDIF,IMPORT,ldiffName,L"",ldifLog);
  145. BREAK_ON_FAILED_HRESULT(hr);
  146. if(stepIt!=NULL)
  147. {
  148. stepIt(ldiffRunStep,caleeStruct);
  149. }
  150. }
  151. // Finally, we run the csv
  152. if (csvActions!=0)
  153. {
  154. String opt=L"-c DOMAINPLACEHOLDER \"" + domain + L"\"";
  155. GetWorkFileName
  156. (
  157. String::load(IDS_FILE_NAME_CSV_LOG),
  158. L"txt",
  159. csvLog
  160. );
  161. hr=runCsvOrLdif(CSV,IMPORT,csvName,opt,csvLog);
  162. BREAK_ON_FAILED_HRESULT(hr);
  163. if(stepIt!=NULL)
  164. {
  165. stepIt(csvRunStep,caleeStruct);
  166. }
  167. }
  168. }
  169. while (0);
  170. LOG_HRESULT(hr);
  171. return hr;
  172. }
  173. // Get the export results of a single object
  174. HRESULT
  175. Repair::getLdifExportedObject(
  176. const long locale,
  177. const String &object,
  178. String &objectLines
  179. )
  180. {
  181. LOG_FUNCTION(Repair::getLdifExportedObject);
  182. ASSERT(!object.empty());
  183. ASSERT(locale > 0);
  184. objectLines.erase();
  185. HRESULT hr=S_OK;
  186. do
  187. {
  188. String dn= L"CN=" + object +
  189. String::format(L",CN=%1!3x!,", locale) +
  190. rootContainerDn;
  191. String opt=L"-o ObjectGuid -d \"" + dn + L"\"";
  192. String tempName;
  193. hr=GetWorkTempFileName(L"TMP",tempName);
  194. BREAK_ON_FAILED_HRESULT(hr);
  195. hr=runCsvOrLdif(LDIF,EXPORT,tempName,opt);
  196. BREAK_ON_FAILED_HRESULT(hr);
  197. hr=ReadAllFile(tempName,objectLines);
  198. BREAK_ON_FAILED_HRESULT(hr);
  199. hr=Win::DeleteFile(tempName);
  200. BREAK_ON_FAILED_HRESULT(hr);
  201. } while(0);
  202. LOG_HRESULT(hr);
  203. return hr;
  204. }
  205. // buildSaveLdif will save information on
  206. // all objects that will be changed
  207. // or deleted in runChangeLdif.
  208. // This includes information on:
  209. // results.objectActions
  210. HRESULT
  211. Repair::buildSaveLdif()
  212. {
  213. LOG_FUNCTION(Repair::buildSaveLdif);
  214. HRESULT hr=S_OK;
  215. HANDLE file;
  216. hr=FS::CreateFile(saveName,
  217. file,
  218. GENERIC_WRITE);
  219. if FAILED(hr)
  220. {
  221. error=String::format(IDS_COULD_NOT_CREATE_FILE,saveName.c_str());
  222. LOG_HRESULT(hr);
  223. return hr;
  224. }
  225. do
  226. {
  227. String objectLines;
  228. ObjectActions::iterator beginObj=results.objectActions.begin();
  229. ObjectActions::iterator endObj=results.objectActions.end();
  230. while(beginObj!=endObj)
  231. {
  232. String dn= L"dn: CN=" + beginObj->first.object +
  233. String::format(L",CN=%1!3x!,", beginObj->first.locale) +
  234. rootContainerDn + L"\r\nchangetype: delete\r\n";
  235. hr=FS::WriteLine(file,dn);
  236. BREAK_ON_FAILED_HRESULT(hr);
  237. hr=getLdifExportedObject(
  238. beginObj->first.locale,
  239. beginObj->first.object,
  240. objectLines
  241. );
  242. BREAK_ON_FAILED_HRESULT(hr);
  243. hr=FS::WriteLine(file,objectLines);
  244. BREAK_ON_FAILED_HRESULT(hr);
  245. if(stepIt!=NULL)
  246. {
  247. stepIt(ldiffSaveStep,caleeStruct);
  248. }
  249. beginObj++;
  250. }
  251. BREAK_ON_FAILED_HRESULT(hr);
  252. beginObj=results.extraneousValues.begin();
  253. endObj=results.extraneousValues.end();
  254. while(beginObj!=endObj)
  255. {
  256. ObjectId tempObj(
  257. beginObj->first.locale,
  258. String(beginObj->first.object)
  259. );
  260. if(
  261. results.objectActions.find(tempObj) ==
  262. results.objectActions.end()
  263. )
  264. {
  265. String dn= L"dn: CN=" + beginObj->first.object +
  266. String::format(L",CN=%1!3x!,", beginObj->first.locale) +
  267. rootContainerDn + L"\r\nchangetype: delete\r\n";
  268. hr=FS::WriteLine(file,dn);
  269. BREAK_ON_FAILED_HRESULT(hr);
  270. hr=getLdifExportedObject(
  271. beginObj->first.locale,
  272. beginObj->first.object,
  273. objectLines
  274. );
  275. BREAK_ON_FAILED_HRESULT(hr);
  276. hr=FS::WriteLine(file,objectLines);
  277. BREAK_ON_FAILED_HRESULT(hr);
  278. }
  279. if(stepIt!=NULL)
  280. {
  281. stepIt(ldiffSaveStep,caleeStruct);
  282. }
  283. beginObj++;
  284. }
  285. BREAK_ON_FAILED_HRESULT(hr);
  286. } while(0);
  287. CloseHandle(file);
  288. LOG_HRESULT(hr);
  289. return hr;
  290. }
  291. HRESULT
  292. Repair::makeObjectsLdif(HANDLE file,ObjectIdList &objects)
  293. {
  294. LOG_FUNCTION(Repair::makeObjectsLdif);
  295. HRESULT hr=S_OK;
  296. do
  297. {
  298. ObjectIdList::iterator begin,end;
  299. String header;
  300. begin=objects.begin();
  301. end=objects.end();
  302. while(begin!=end)
  303. {
  304. header= L"\r\ndn: CN=" + begin->object +
  305. String::format(L",CN=%1!3x!,", begin->locale) +
  306. rootContainerDn;
  307. hr=FS::WriteLine(file,header);
  308. BREAK_ON_FAILED_HRESULT(hr);
  309. hr=FS::WriteLine(file,L"changetype: delete");
  310. BREAK_ON_FAILED_HRESULT(hr);
  311. begin++;
  312. if(stepIt!=NULL)
  313. {
  314. stepIt(ldiffBuildStep,caleeStruct);
  315. }
  316. }
  317. BREAK_ON_FAILED_HRESULT(hr);
  318. } while(0);
  319. LOG_HRESULT(hr);
  320. return hr;
  321. }
  322. // buildChangeLdif wil build the Ldif that
  323. // will change the objects saved im
  324. // buildSaveLdif
  325. HRESULT
  326. Repair::buildChangeLdif()
  327. {
  328. LOG_FUNCTION(Repair::buildChangeLdif);
  329. HRESULT hr=S_OK;
  330. HANDLE file;
  331. hr=FS::CreateFile(ldiffName,
  332. file,
  333. GENERIC_WRITE);
  334. if FAILED(hr)
  335. {
  336. error=String::format(IDS_COULD_NOT_CREATE_FILE,ldiffName.c_str());
  337. LOG_HRESULT(hr);
  338. return hr;
  339. }
  340. do
  341. {
  342. String header;
  343. String line;
  344. ObjectActions::iterator beginObj=results.objectActions.begin();
  345. ObjectActions::iterator endObj=results.objectActions.end();
  346. while(beginObj!=endObj)
  347. {
  348. header= L"\r\ndn: CN=" + beginObj->first.object +
  349. String::format(L",CN=%1!3x!,", beginObj->first.locale) +
  350. rootContainerDn;
  351. hr=FS::WriteLine(file,header);
  352. BREAK_ON_FAILED_HRESULT(hr);
  353. hr=FS::WriteLine(file,L"changetype: ntdsSchemaModify");
  354. BREAK_ON_FAILED_HRESULT(hr);
  355. PropertyActions::iterator beginAct=beginObj->second.begin();
  356. PropertyActions::iterator endAct=beginObj->second.end();
  357. while(beginAct!=endAct)
  358. {
  359. if(!beginAct->second.addValues.empty())
  360. {
  361. line = L"add: " + beginAct->first;
  362. hr=FS::WriteLine(file,line);
  363. BREAK_ON_FAILED_HRESULT(hr);
  364. StringList::iterator
  365. beginAdd = beginAct->second.addValues.begin();
  366. StringList::iterator
  367. endAdd = beginAct->second.addValues.end();
  368. while(beginAdd!=endAdd)
  369. {
  370. line = beginAct->first + L": " + *beginAdd;
  371. hr=FS::WriteLine(file,line);
  372. BREAK_ON_FAILED_HRESULT(hr);
  373. beginAdd++;
  374. }
  375. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  376. hr=FS::WriteLine(file,L"-");
  377. BREAK_ON_FAILED_HRESULT(hr);
  378. }
  379. if(!beginAct->second.delValues.empty())
  380. {
  381. line = L"delete: " + beginAct->first;
  382. hr=FS::WriteLine(file,line);
  383. BREAK_ON_FAILED_HRESULT(hr);
  384. StringList::iterator
  385. beginDel = beginAct->second.delValues.begin();
  386. StringList::iterator
  387. endDel = beginAct->second.delValues.end();
  388. while(beginDel!=endDel)
  389. {
  390. line = beginAct->first + L": " + *beginDel;
  391. hr=FS::WriteLine(file,line);
  392. BREAK_ON_FAILED_HRESULT(hr);
  393. beginDel++;
  394. }
  395. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  396. hr=FS::WriteLine(file,L"-");
  397. BREAK_ON_FAILED_HRESULT(hr);
  398. }
  399. beginAct++;
  400. } // while(beginAct!=endAct)
  401. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  402. if(stepIt!=NULL)
  403. {
  404. stepIt(ldiffBuildStep,caleeStruct);
  405. }
  406. beginObj++;
  407. } // while(beginObj!=endObj)
  408. BREAK_ON_FAILED_HRESULT(hr);
  409. // Now we will add actions to remove the extraneous objects
  410. beginObj=results.extraneousValues.begin();
  411. endObj=results.extraneousValues.end();
  412. while(beginObj!=endObj)
  413. {
  414. header= L"\r\ndn: CN=" + beginObj->first.object +
  415. String::format(L",CN=%1!3x!,", beginObj->first.locale) +
  416. rootContainerDn;
  417. hr=FS::WriteLine(file,header);
  418. BREAK_ON_FAILED_HRESULT(hr);
  419. hr=FS::WriteLine(file,L"changetype: ntdsSchemaModify");
  420. BREAK_ON_FAILED_HRESULT(hr);
  421. PropertyActions::iterator beginAct=beginObj->second.begin();
  422. PropertyActions::iterator endAct=beginObj->second.end();
  423. while(beginAct!=endAct)
  424. {
  425. if(!beginAct->second.delValues.empty())
  426. {
  427. line = L"delete: " + beginAct->first;
  428. hr=FS::WriteLine(file,line);
  429. BREAK_ON_FAILED_HRESULT(hr);
  430. StringList::iterator
  431. beginDel = beginAct->second.delValues.begin();
  432. StringList::iterator
  433. endDel = beginAct->second.delValues.end();
  434. while(beginDel!=endDel)
  435. {
  436. line = beginAct->first + L": " + *beginDel;
  437. hr=FS::WriteLine(file,line);
  438. BREAK_ON_FAILED_HRESULT(hr);
  439. beginDel++;
  440. }
  441. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  442. hr=FS::WriteLine(file,L"-");
  443. BREAK_ON_FAILED_HRESULT(hr);
  444. } //if(!beginAct->second.delValues.empty())
  445. beginAct++;
  446. } // while(beginAct!=endAct)
  447. BREAK_ON_FAILED_HRESULT(hr);
  448. if(stepIt!=NULL)
  449. {
  450. stepIt(ldiffBuildStep,caleeStruct);
  451. }
  452. beginObj++;
  453. } // while(beginObj!=endObj)
  454. BREAK_ON_FAILED_HRESULT(hr);
  455. } while(0);
  456. CloseHandle(file);
  457. LOG_HRESULT(hr);
  458. return hr;
  459. }
  460. HRESULT
  461. Repair::makeObjectsCsv(HANDLE file,ObjectIdList &objects)
  462. {
  463. LOG_FUNCTION(Repair::makeObjectsCsv);
  464. HRESULT hr=S_OK;
  465. do
  466. {
  467. ObjectIdList::iterator begin,end;
  468. begin=objects.begin();
  469. end=objects.end();
  470. while(begin!=end)
  471. {
  472. long locale=begin->locale;
  473. const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
  474. setOfObjects tempObjs;
  475. pair<String,long> tempObj;
  476. tempObj.first=begin->object;
  477. tempObj.second=begin->locale;
  478. tempObjs.insert(tempObj);
  479. hr=csvReader.makeObjectsCsv(file,tempObjs);
  480. BREAK_ON_FAILED_HRESULT(hr);
  481. begin++;
  482. if(stepIt!=NULL)
  483. {
  484. stepIt(csvBuildStep,caleeStruct);
  485. }
  486. }
  487. BREAK_ON_FAILED_HRESULT(hr);
  488. } while(0);
  489. LOG_HRESULT(hr);
  490. return hr;
  491. }
  492. // buildCsv creates a CSV with:
  493. // results.createContainers,
  494. // results.createW2KObjects
  495. // results.createXPObjects
  496. HRESULT
  497. Repair::buildCsv()
  498. {
  499. LOG_FUNCTION(Repair::buildCsv);
  500. HANDLE file;
  501. HRESULT hr=S_OK;
  502. hr=FS::CreateFile(csvName,
  503. file,
  504. GENERIC_WRITE);
  505. if FAILED(hr)
  506. {
  507. error=String::format(IDS_COULD_NOT_CREATE_FILE,csvName.c_str());
  508. LOG_HRESULT(hr);
  509. return hr;
  510. }
  511. do
  512. {
  513. LongList::iterator bgCont,endCont;
  514. bgCont=results.createContainers.begin();
  515. endCont=results.createContainers.end();
  516. while(bgCont!=endCont)
  517. {
  518. long locale=*bgCont;
  519. const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
  520. long locales[2]={locale,0L};
  521. hr=csvReader.makeLocalesCsv(file,locales);
  522. BREAK_ON_FAILED_HRESULT(hr);
  523. bgCont++;
  524. if(stepIt!=NULL)
  525. {
  526. stepIt(csvBuildStep,caleeStruct);
  527. }
  528. }
  529. BREAK_ON_FAILED_HRESULT(hr);
  530. hr=makeObjectsCsv(file,results.createW2KObjects);
  531. BREAK_ON_FAILED_HRESULT(hr);
  532. hr=makeObjectsCsv(file,results.createXPObjects);
  533. BREAK_ON_FAILED_HRESULT(hr);
  534. } while(0);
  535. CloseHandle(file);
  536. LOG_HRESULT(hr);
  537. return hr;
  538. }
  539. // This finction will run csvde or ldifde(whichExe)
  540. // to import or export (inOut) file. The options specified
  541. // are -u for unicode, -j for the log/err path -f for the file
  542. // -i if import and the extraOptions.
  543. // The log file will be renamed for logFileArg(if !empty)
  544. // If an error file is generated it will be renamed.
  545. HRESULT
  546. Repair::runCsvOrLdif(
  547. csvOrLdif whichExe,
  548. importExport inOut,
  549. const String& file,
  550. const String& extraOptions,//=L""
  551. const String& logFileArg//=L""
  552. )
  553. {
  554. LOG_FUNCTION2(Repair::runCsvOrLdif,file.c_str());
  555. String baseName = (whichExe==LDIF) ? L"LDIF" : L"CSV";
  556. String exeName = baseName + L"de.exe";
  557. String options = (inOut==IMPORT) ? L"-i " + extraOptions : extraOptions;
  558. String operation = (inOut==IMPORT) ? L"importing" : L"exporting";
  559. HRESULT hr=S_OK;
  560. do
  561. {
  562. String sys32dir = Win::GetSystemDirectory();
  563. String wholeName = sys32dir + L"\\" + exeName;
  564. if (!FS::FileExists(wholeName))
  565. {
  566. error=String::format(IDS_EXE_NOT_FOUND,wholeName.c_str());
  567. hr=E_FAIL;
  568. break;
  569. }
  570. if (inOut==IMPORT && !FS::FileExists(file))
  571. {
  572. hr=Win32ToHresult(ERROR_FILE_NOT_FOUND);
  573. error=file;
  574. break;
  575. }
  576. String commandLine = L"\"" + wholeName + L"\" " +
  577. options +
  578. L" -u -f \"" +
  579. file +
  580. L"\" -j \"" +
  581. logPath + L"\"";
  582. STARTUPINFO si;
  583. PROCESS_INFORMATION pi;
  584. GetStartupInfo(&si);
  585. String curDir=L"";
  586. String errFile=logPath + L"\\" + baseName + L".err";
  587. String logFile=logPath + L"\\" + baseName + L".log";
  588. if(FS::FileExists(errFile))
  589. {
  590. hr=Win::DeleteFile(errFile);
  591. BREAK_ON_FAILED_HRESULT_ERROR(hr,errFile);
  592. }
  593. if(FS::FileExists(logFile))
  594. {
  595. hr=Win::DeleteFile(logFile);
  596. BREAK_ON_FAILED_HRESULT_ERROR(hr,logFile);
  597. }
  598. hr=Win::CreateProcess
  599. (
  600. commandLine,
  601. NULL, // lpProcessAttributes
  602. NULL, // lpThreadAttributes
  603. false, // dwCreationFlags
  604. NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,// fdwCreate
  605. NULL, // lpEnvironment
  606. curDir, // lpEnvironment
  607. si, // [in] lpStartupInfo
  608. pi // [out] pProcessInformation
  609. );
  610. BREAK_ON_FAILED_HRESULT_ERROR(hr,
  611. String::format(IDS_COULD_NOT_START_EXE,commandLine.c_str()));
  612. String errorInfo=String::format
  613. (
  614. IDS_CSVDE_LDIFDE_ERROR_BASIC,
  615. operation.c_str(),
  616. exeName.c_str(),
  617. commandLine.c_str()
  618. );
  619. do
  620. {
  621. DWORD resWait;
  622. hr=Win::WaitForSingleObject(pi.hProcess,INFINITE,resWait);
  623. BREAK_ON_FAILED_HRESULT_ERROR(hr,errorInfo);
  624. if(!logFileArg.empty())
  625. {
  626. hr=FS::MoveFile(logFile.c_str(), logFileArg.c_str());
  627. BREAK_ON_FAILED_HRESULT_ERROR(hr,logFile);
  628. }
  629. DWORD resExit;
  630. hr=Win::GetExitCodeProcess(pi.hProcess,resExit);
  631. BREAK_ON_FAILED_HRESULT_ERROR(hr,errorInfo);
  632. if(resExit!=0)
  633. {
  634. String betterErrFile;
  635. GetWorkFileName
  636. (
  637. String::load(
  638. (whichExe==LDIF) ?
  639. IDS_FILE_NAME_LDIF_ERROR :
  640. IDS_FILE_NAME_CSV_ERROR
  641. ),
  642. L"txt",
  643. betterErrFile
  644. );
  645. hr=FS::MoveFile(errFile.c_str(), betterErrFile.c_str());
  646. BREAK_ON_FAILED_HRESULT_ERROR(hr,errFile);
  647. error=String::format
  648. (
  649. IDS_CSVDE_LDIFDE_ERROR_COMPLETE,
  650. operation.c_str(),
  651. exeName.c_str(),
  652. commandLine.c_str(),
  653. betterErrFile.c_str()
  654. );
  655. hr=E_FAIL;
  656. break;
  657. }
  658. } while(0);
  659. CloseHandle(pi.hProcess);
  660. CloseHandle(pi.hThread);
  661. } while(0);
  662. LOG_HRESULT(hr);
  663. return hr;
  664. }