Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

Utility.cc 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. //
  2. // Utility.cc
  3. //
  4. // Utility functions for BuildDistribution.
  5. //
  6. // (C) Copyright 2010 ARM Research Labs, LLC See
  7. // www.armresearch.com for the copyright terms.
  8. //
  9. // $Id$
  10. //
  11. #include <windows.h>
  12. #include <tchar.h>
  13. #include <string>
  14. #include <iostream>
  15. #include <stdexcept>
  16. #include <algorithm>
  17. #include <sstream>
  18. #include <iterator>
  19. #include "Utility.h"
  20. static DWORD LastError = 0; // Last value from GetLastError(). Needed because
  21. // GetLastError() doesn't return the correct value
  22. // after an exception is thrown.
  23. void
  24. OutputUsage(std::string DefaultTempPath) {
  25. std::cout <<
  26. "\n"
  27. "Usage:\n"
  28. "\n"
  29. " BuildDistribution -d DistPath -t TempPath\n"
  30. "\n"
  31. " where DistPath is the path of the distribution\n"
  32. " (e.g. SNFMultiSDK_Windows_3.1, and TempPath is the name of the\n"
  33. " directory to use for temporary storage. TempPath must exist.\n"
  34. " The default value of TempPath is '" << DefaultTempPath << "'.\n"
  35. ;
  36. }
  37. void
  38. OutputHelp() {
  39. std::cout <<
  40. "\n"
  41. "The program does the following:\n"
  42. "\n"
  43. " 1) For each directory DIR that appears in DistPath and also in\n"
  44. " DistPath\\..:\n"
  45. "\n"
  46. " a) Delete the contents of DistPath/DIR, except for .svn.\n"
  47. "\n"
  48. " b) Copy the contents of DistPath\\..\\DIR to DistPath\\DIR, except\n"
  49. " for .svn.\n"
  50. "\n"
  51. " 2) Create a temporary directory TempPath/DistName, where DistName is\n"
  52. " the directory name of DistPath (e.g. if DistName is\n"
  53. " c:\\dir1\\dir2\\SNFMultiSDK_Windows_3.1, then DistName is\n"
  54. " SNFMultiSDK_Windows_3.1).\n"
  55. "\n"
  56. " 3) For each directory DIR that appears in DistPath and also in\n"
  57. " DistPath\\..:\n"
  58. "\n"
  59. " a) Copy all files from DistPath/DIR to TempPath/DistName, except\n"
  60. " for .svn.\n\n"
  61. ;
  62. }
  63. void
  64. OutputErrorMessage(std::string Message) {
  65. LPVOID lpMsgBuf;
  66. if (LastError != 0) {
  67. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  68. FORMAT_MESSAGE_FROM_SYSTEM |
  69. FORMAT_MESSAGE_IGNORE_INSERTS,
  70. NULL,
  71. LastError,
  72. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  73. (LPTSTR) &lpMsgBuf,
  74. 0,
  75. NULL);
  76. std::cerr << Message << ": " << (LPCSTR) lpMsgBuf;
  77. } else {
  78. std::cerr << Message << "\n";
  79. }
  80. }
  81. /// Case-insensitive search for a specified string in a container of strings.
  82. //
  83. // \param[in] Needle is the string to search for.
  84. //
  85. // \param[in] Haystack is the container of strings to search.
  86. //
  87. // \returns true if Needle is in Haystack (case-insensitive
  88. // comparison), false otherwise.
  89. //
  90. bool IsInContainer(std::string Needle, StringContainer Haystack);
  91. /// Get a list of directories in a specified path.
  92. //
  93. // This function returns a list of directories in the specified path,
  94. // excluding a specified list of names.
  95. //
  96. // \param[in] DistPath is the path to search.
  97. //
  98. // \param[in] ExcludeName contains the names to exclude.
  99. //
  100. // \returns a list of directory names in the specified path, excluding
  101. // names in ExcludeNames.
  102. //
  103. StringContainer GetDirectoryList(std::string DistPath,
  104. StringContainer ExcludeName);
  105. /// Get a list of files in a specified path.
  106. //
  107. // This function returns a list of files in the specified path,
  108. // excluding a specified list of names.
  109. //
  110. // \param[in] DistPath is the path to search.
  111. //
  112. // \param[in] ExcludeName contains the names to exclude.
  113. //
  114. // \returns a list of file names in the specified path,
  115. // excluding names in ExcludeNames.
  116. //
  117. StringContainer GetFileList(std::string DistPath,
  118. StringContainer ExcludeName);
  119. /// Update the files in one directory.
  120. //
  121. // \param[in] SourceDir is the name of the directory that contains the
  122. // files to copy from.
  123. //
  124. // \param[in] DestDir is the name of the directory to clear and copy
  125. // files to.
  126. //
  127. // \param[in] ExcludeName contains the names of the files to not
  128. // delete or copy.
  129. //
  130. // This function:
  131. //
  132. // 1) Deletes the files in DestDir, except for ExcludeName and directories.
  133. //
  134. // 2) If a directory in exists in both SourceDir and DestDir, then
  135. // update that directory by invoking UpdateCommonDirectories().
  136. //
  137. // 3) If a directory exists in DestDir but not in SourceDir, delete
  138. // that directory and all it's contents.
  139. //
  140. // 4) Copy the non-directory files SourceDir to DestDir, except for
  141. // ExcludeName.
  142. //
  143. void UpdateOneDirectory(std::string SourceDir,
  144. std::string DestDir,
  145. StringContainer ExcludeName);
  146. /// Delete a directory and all it's contents.
  147. //
  148. // This function recursively deletes the contents of a directory, and
  149. // then deletes the directory.
  150. //
  151. // \param[in] Path is the path to delete.
  152. //
  153. void DeletePath(std::string Path);
  154. void
  155. GetDirectoryNames(std::string &InputDistPath,
  156. std::string &DistSourcePath,
  157. std::string &DistParentPath,
  158. std::string &DistName) {
  159. DWORD RetVal = 0;
  160. TCHAR PathPart[MAX_PATH];
  161. LPTSTR FilePart = NULL;
  162. RetVal = GetFullPathName(InputDistPath.c_str(), // Get the path name for the source.
  163. MAX_PATH,
  164. PathPart,
  165. &FilePart);
  166. LastError = GetLastError();
  167. if (0 == RetVal) {
  168. throw(std::invalid_argument("Error determining directory names"));
  169. }
  170. DistSourcePath = PathPart;
  171. if ( (NULL != FilePart) && (0 != *FilePart) ) { // Extract the distribution name
  172. // (last component of the source path.
  173. DistName = FilePart;
  174. } else {
  175. throw(std::invalid_argument("Unable to determine distribution name"));
  176. }
  177. std::string::size_type DistNameIndex; // Get the parent directory of the
  178. // source directory.
  179. DistNameIndex = DistSourcePath.rfind("\\");
  180. if (std::string::npos == DistNameIndex) {
  181. throw(std::invalid_argument("Unable to determine the name of the "
  182. "distribution parent directory"));
  183. }
  184. DistParentPath = DistSourcePath.substr(0, DistNameIndex);
  185. }
  186. bool
  187. IsInContainer(std::string Needle, StringContainer Haystack) {
  188. std::transform(Needle.begin(), Needle.end(), Needle.begin(), ::toupper);
  189. StringContainer::iterator iFile;
  190. for (iFile = Haystack.begin(); iFile != Haystack.end(); iFile++) { // Check each file in the container.
  191. std::transform(iFile->begin(), iFile->end(), iFile->begin(), ::toupper);
  192. if (*iFile == Needle) {
  193. return true;
  194. }
  195. }
  196. return false;
  197. }
  198. StringContainer
  199. GetDirectoryList(std::string DistPath, StringContainer ExcludeName) {
  200. DistPath += "\\*.*"; // Create filter string.
  201. WIN32_FIND_DATA FileData;
  202. HANDLE ListHandle;
  203. std::string FileName;
  204. ListHandle = FindFirstFile(DistPath.c_str(),
  205. &FileData);
  206. StringContainer DirName; // Container to hold directory
  207. // names of the distribution.
  208. if ( (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && // Is this a directory...
  209. (! IsInContainer(FileData.cFileName, ExcludeName)) ) { // ...and not an excluded file?
  210. DirName.push_back(FileData.cFileName); // Yes. Save the name.
  211. }
  212. while (true) {
  213. if (FindNextFile(ListHandle, &FileData)) {
  214. if ( (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && // Is this a directory...
  215. (! IsInContainer(FileData.cFileName, ExcludeName)) ) { // ...and not an excluded file?
  216. DirName.push_back(FileData.cFileName); // Yes. Save the name.
  217. }
  218. } else {
  219. LastError = GetLastError();
  220. if (ERROR_NO_MORE_FILES == LastError) {
  221. break;
  222. } else {
  223. std::ostringstream temp;
  224. temp << "Error determining directory list of '"
  225. << DistPath << "'";
  226. throw(std::runtime_error(temp.str()));
  227. }
  228. }
  229. }
  230. if (FindClose(ListHandle) == 0) {
  231. std::ostringstream Temp;
  232. LastError = GetLastError();
  233. Temp << "***Error closing handle for " << DistPath;
  234. throw(std::runtime_error(Temp.str()));
  235. }
  236. return DirName;
  237. }
  238. StringContainer
  239. GetFileList(std::string DirPath, StringContainer ExcludeName) {
  240. std::string DirPathFilter;
  241. DirPathFilter = DirPath + "\\*.*"; // Create filter string.
  242. WIN32_FIND_DATA FileData;
  243. HANDLE ListHandle;
  244. ListHandle = FindFirstFile(DirPathFilter.c_str(),
  245. &FileData);
  246. StringContainer FileNameList; // Container to hold file names.
  247. std::string FileName;
  248. if ( !(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && // Is this not a directory...
  249. (! IsInContainer(FileData.cFileName, ExcludeName)) ) { // ...and not an excluded file?
  250. FileNameList.push_back(FileData.cFileName); // Yes. Save the name.
  251. }
  252. while (true) {
  253. if (FindNextFile(ListHandle, &FileData)) {
  254. if ( !(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && // Is this not a directory...
  255. (! IsInContainer(FileData.cFileName, ExcludeName)) ) { // ...and not an excluded file?
  256. FileNameList.push_back(FileData.cFileName); // Yes. Save the name.
  257. }
  258. } else {
  259. LastError = GetLastError();
  260. if (ERROR_NO_MORE_FILES == LastError) {
  261. break;
  262. } else {
  263. std::ostringstream temp;
  264. temp << "Error determining directory list of '"
  265. << DirPath << "'";
  266. throw(std::runtime_error(temp.str()));
  267. }
  268. }
  269. }
  270. if (FindClose(ListHandle) == 0) {
  271. std::ostringstream Temp;
  272. LastError = GetLastError();
  273. Temp << "***Error closing handle for " << DirPath;
  274. throw(std::runtime_error(Temp.str()));
  275. }
  276. return FileNameList;
  277. }
  278. void
  279. UpdateOneDirectory(std::string SourceDir,
  280. std::string DestDir,
  281. StringContainer ExcludeName) {
  282. StringContainer DestDirFileList; // Files in DestDir.
  283. DestDirFileList = GetFileList(DestDir, ExcludeName);
  284. StringContainer::iterator iFile;
  285. std::string FileToDelete;
  286. for (iFile = DestDirFileList.begin(); // Remove the files.
  287. iFile != DestDirFileList.end();
  288. iFile++) {
  289. if (! IsInContainer(*iFile, ExcludeName)) { // Check if this file is in ExcludeName.
  290. FileToDelete = DestDir + "\\"; // It is not. Delete it.
  291. FileToDelete += *iFile;
  292. if (DeleteFile(FileToDelete.c_str()) == 0) {
  293. std::ostringstream Temp;
  294. LastError = GetLastError();
  295. Temp << "***Error deleting " << FileToDelete;
  296. throw(std::runtime_error(Temp.str()));
  297. }
  298. }
  299. }
  300. StringContainer SourceDirFileList; // Files in SourceDir.
  301. std::string SourceFile, DestFile;
  302. SourceDirFileList = GetFileList(SourceDir, ExcludeName);
  303. for (iFile = SourceDirFileList.begin(); // Copy the files from SourceDir.
  304. iFile != SourceDirFileList.end();
  305. iFile++) {
  306. if (! IsInContainer(*iFile, ExcludeName)) { // Check if this file is in ExcludeName.
  307. SourceFile = SourceDir + "\\"; // It is not. Copy it.
  308. SourceFile += *iFile;
  309. DestFile = DestDir + "\\";
  310. DestFile += *iFile;
  311. if (CopyFile(SourceFile.c_str(), DestFile.c_str(), true) == 0) {
  312. std::ostringstream Temp;
  313. LastError = GetLastError();
  314. Temp << "Error copying " << SourceFile << " to " << DestFile;
  315. throw(std::runtime_error(Temp.str()));
  316. }
  317. }
  318. }
  319. StringContainer SourceDirDirList, DestDirDirList;
  320. std::string SourceUpdateDir, DestUpdateDir;
  321. StringContainer SourceDirExtraDirList, DestDirExtraDirList;
  322. SourceDirDirList = GetDirectoryList(SourceDir, ExcludeName);
  323. DestDirDirList = GetDirectoryList(DestDir, ExcludeName);
  324. for (iFile = DestDirDirList.begin(); // Check that all directories in
  325. iFile != DestDirDirList.end(); // the destination directory are
  326. iFile++) { // also in the source directory.
  327. if (! IsInContainer(*iFile, SourceDirDirList)) { // Not in source directory?
  328. DestDirExtraDirList.push_back(*iFile); // It is not. This is an error.
  329. }
  330. }
  331. for (iFile = SourceDirDirList.begin(); // Check that all directories in
  332. iFile != SourceDirDirList.end(); // the source directory are also
  333. iFile++) { // in the destination directory.
  334. if (! IsInContainer(*iFile, DestDirDirList)) { // Not in source directory?
  335. SourceDirExtraDirList.push_back(*iFile); // It is not. This is an error.
  336. }
  337. }
  338. if (!SourceDirExtraDirList.empty() || !DestDirExtraDirList.empty()) { // Check for error.
  339. std::ostringstream Temp;
  340. if (!SourceDirExtraDirList.empty()) { // Extra directories in source.
  341. Temp << "***Error--There were directories in " << SourceDir
  342. << " that are not in " << DestDir << ":\n\t";
  343. std::copy(SourceDirExtraDirList.begin(),
  344. SourceDirExtraDirList.end(),
  345. std::ostream_iterator<std::string>(Temp, "\n\t"));
  346. }
  347. if (!DestDirExtraDirList.empty()) { // Extra directories in destination.
  348. Temp << "***Error--There were directories in " << DestDir
  349. << " that are not in " << SourceDir << ":\n\t";
  350. std::copy(DestDirExtraDirList.begin(),
  351. DestDirExtraDirList.end(),
  352. std::ostream_iterator<std::string>(Temp, "\n\t"));
  353. }
  354. throw(std::runtime_error(Temp.str()));
  355. }
  356. for (iFile = DestDirDirList.begin(); // Update each directory.
  357. iFile != DestDirDirList.end();
  358. iFile++) {
  359. SourceUpdateDir = SourceDir + "\\";
  360. SourceUpdateDir += *iFile;
  361. DestUpdateDir = DestDir + "\\";
  362. DestUpdateDir += *iFile;
  363. UpdateOneDirectory(SourceUpdateDir, DestUpdateDir, ExcludeName);
  364. }
  365. }
  366. void
  367. UpdateCommonDirectories(std::string DistPath, std::string DistParentPath,
  368. StringContainer ExcludeName) {
  369. StringContainer DistDirList, DistParentDirList;
  370. DistDirList = GetDirectoryList(DistPath, ExcludeName); // Distribution directory names.
  371. DistParentDirList = GetDirectoryList(DistParentPath, ExcludeName); // Parent of distribution directory names.
  372. #if 0
  373. // DEBUG.
  374. std::cout << "Directory list of distribution--\n";
  375. std::copy(DistDirList.begin(),
  376. DistDirList.end(),
  377. std::ostream_iterator<std::string>(std::cout, "\n"));
  378. std::cout << "\nDirectory list of distribution parent--\n";
  379. std::copy(DistParentDirList.begin(),
  380. DistParentDirList.end(),
  381. std::ostream_iterator<std::string>(std::cout, "\n"));
  382. // END OF DEBUG.
  383. #endif
  384. StringContainer::iterator iDistDir; // Update direcotries with the same name.
  385. for (iDistDir = DistDirList.begin();
  386. iDistDir != DistDirList.end();
  387. iDistDir++) {
  388. std::string SourceDir, DestDir;
  389. if (IsInContainer(*iDistDir, DistParentDirList)) { // Check if this is a common directory.
  390. SourceDir = DistParentPath + "\\"; // This is a common directory.
  391. SourceDir += *iDistDir;
  392. DestDir = DistPath + "\\";
  393. DestDir += *iDistDir;
  394. UpdateOneDirectory(SourceDir, DestDir, ExcludeName);
  395. }
  396. }
  397. return;
  398. }
  399. void
  400. PrepareTempDir(std::string TempPath) {
  401. WIN32_FIND_DATA FileData;
  402. DWORD LastError;
  403. HANDLE DirHandle;
  404. std::ostringstream Temp;
  405. DirHandle = FindFirstFile(TempPath.c_str(), &FileData); // Check whether the directory exists.
  406. if (INVALID_HANDLE_VALUE == DirHandle) { // Directory doesn't exist.
  407. if (!CreateDirectory(TempPath.c_str(), NULL)) {
  408. LastError = GetLastError();
  409. Temp << "***Error creating the temporary directory " << TempPath;
  410. throw(std::runtime_error(Temp.str()));
  411. }
  412. return;
  413. }
  414. // If the path is a file, delete it and create a new directory.
  415. if ( !(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  416. if (CloseHandle(DirHandle) != 0) {
  417. LastError = GetLastError();
  418. Temp << "***Error closing handle for " << TempPath;
  419. throw(std::runtime_error(Temp.str()));
  420. }
  421. if (DeleteFile(TempPath.c_str()) != 0) {
  422. LastError = GetLastError();
  423. Temp << "***Error deleting " << TempPath;
  424. throw(std::runtime_error(Temp.str()));
  425. }
  426. PrepareTempDir(TempPath);
  427. return;
  428. }
  429. if (CloseHandle(DirHandle) != 0) {
  430. LastError = GetLastError();
  431. Temp << "***Error closing handle for " << TempPath;
  432. throw(std::runtime_error(Temp.str()));
  433. }
  434. DeletePath(TempPath); // TempPath is a directory. Delete it.
  435. PrepareTempDir(TempPath); // Create an empty directory.
  436. }
  437. void
  438. DeletePath(std::string Path) {
  439. StringContainer DirList, FileList, ExcludeName;
  440. StringContainer::iterator iName;
  441. std::string NameToDelete;
  442. ExcludeName.push_back(".");
  443. ExcludeName.push_back("..");
  444. DirList = GetDirectoryList(Path, ExcludeName);
  445. FileList = GetFileList(Path, ExcludeName);
  446. for (iName = FileList.begin(); // Delete each file.
  447. iName != FileList.end();
  448. iName++) {
  449. NameToDelete = Path + "\\";
  450. NameToDelete += *iName;
  451. if (DeleteFile(NameToDelete.c_str()) == 0) {
  452. std::ostringstream Temp;
  453. LastError = GetLastError();
  454. Temp << "***Error deleting " << NameToDelete << " in " << Path;
  455. throw(std::runtime_error(Temp.str()));
  456. }
  457. }
  458. for (iName = DirList.begin(); // Delete each directory.
  459. iName != DirList.end();
  460. iName++) {
  461. NameToDelete = Path + "\\";
  462. NameToDelete += *iName;
  463. DeletePath(NameToDelete);
  464. }
  465. if (RemoveDirectory(Path.c_str()) == 0) {
  466. std::ostringstream Temp;
  467. LastError = GetLastError();
  468. Temp << "***Error removing directory " << Path;
  469. throw(std::runtime_error(Temp.str()));
  470. }
  471. }
  472. void
  473. CopyDirectory(std::string SourcePath, std::string DestPath, StringContainer ExcludeName) {
  474. StringContainer DirList, FileList;
  475. StringContainer::iterator iName;
  476. std::string SourceName, DestName;
  477. BOOL FailIfExists = true;
  478. DirList = GetDirectoryList(SourcePath, ExcludeName);
  479. FileList = GetFileList(SourcePath, ExcludeName);
  480. for (iName = FileList.begin(); // Copy each file.
  481. iName != FileList.end();
  482. iName++) {
  483. SourceName = SourcePath + "\\";
  484. SourceName += *iName;
  485. DestName = DestPath + "\\";
  486. DestName += *iName;
  487. if (!CopyFile(SourceName.c_str(), DestName.c_str(), FailIfExists)) {
  488. std::ostringstream Temp;
  489. LastError = GetLastError();
  490. Temp << "Error copying " << *iName << " to " << DestPath;
  491. throw(std::runtime_error(Temp.str()));
  492. }
  493. }
  494. for (iName = DirList.begin(); // Copy each directory.
  495. iName != DirList.end();
  496. iName++) {
  497. SourceName = SourcePath + "\\";
  498. SourceName += *iName;
  499. DestName = DestPath + "\\";
  500. DestName += *iName;
  501. if (!CreateDirectory(DestName.c_str(), NULL)) { // Create the directory.
  502. std::ostringstream Temp;
  503. LastError = GetLastError();
  504. Temp << "***Error creating the temporary directory " << DestName;
  505. throw(std::runtime_error(Temp.str()));
  506. }
  507. CopyDirectory(SourceName, DestName, ExcludeName);
  508. }
  509. }