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.

544 lines
13 KiB

  1. /*
  2. Copy a build from a vbl share to the local machine, in order to
  3. PopulateFromVBL from the local copy.
  4. Usage:
  5. popcopy -option
  6. popcopy -nooption
  7. popcopy -option:value
  8. popcopy -option=value
  9. Options:
  10. -from (required)
  11. -to (required)
  12. -nosym (default)
  13. -symonly
  14. -sym
  15. -bat (prints a .bat file instead of running commands)
  16. -nocopy (hack so to simulate "-localuncomponly" so I can debug it)
  17. Jay Krell
  18. May 3, 2001
  19. */
  20. #pragma warning(disable:4786) // identifier was truncated to '255' character
  21. #include "stdinc.h"
  22. #include <vector>
  23. #include <map>
  24. #include <string>
  25. #include <iterator>
  26. #include <stdlib.h>
  27. #include <set>
  28. #include <fstream>
  29. #include <algorithm>
  30. #include <time.h>
  31. #include "windows.h"
  32. #include "setupapi.h"
  33. const std::string::size_type npos = std::string::npos;
  34. class String_t : public std::string
  35. //
  36. // 1) comparison is case insensitive
  37. // 2) MAYBE slashes sort like \1, but not currently
  38. //
  39. {
  40. typedef std::string Base_t;
  41. public:
  42. String_t() { }
  43. ~String_t() { }
  44. String_t(const Base_t& s) : Base_t(s) { }
  45. String_t(const char* s) : Base_t(s) { }
  46. void operator=(const char* s) { Base_t::operator=(s); }
  47. void operator=(const std::string& s) { Base_t::operator=(s); }
  48. //operator const char*() const { return c_str(); }
  49. bool operator<(const char* t) const
  50. {
  51. return _stricmp(c_str(), t) < 0;
  52. }
  53. bool operator==(const char* t) const
  54. {
  55. return _stricmp(c_str(), t) == 0;
  56. }
  57. bool operator<(const std::string& t) const
  58. {
  59. return operator<(t.c_str());
  60. }
  61. bool operator==(const std::string& t) const
  62. {
  63. return operator==(t.c_str());
  64. }
  65. void MakeLower()
  66. {
  67. for (iterator i = begin() ; i != end() ; ++i)
  68. {
  69. *i = static_cast<char>(tolower(*i));
  70. }
  71. }
  72. };
  73. typedef std::vector<String_t> StringVector_t;
  74. typedef std::set<String_t> StringSet_t;
  75. typedef std::map<String_t, String_t> StringToStringMap_t;
  76. bool IsTrue(const String_t& s)
  77. {
  78. return (s == "1" || s == "true" || s == "True" || s == "TRUE"); }
  79. bool IsFalse(const String_t& s)
  80. {
  81. return (s == "" || s == "0" || s == "false" || s == "False" || s == "FALSE"); }
  82. void CommandLineError(
  83. const String_t& e
  84. )
  85. {
  86. fprintf(stderr, "%s\n", e.c_str());
  87. exit(EXIT_FAILURE);
  88. }
  89. class Binlist_t
  90. {
  91. public:
  92. Binlist_t() { }
  93. ~Binlist_t() { }
  94. StringVector_t m_files;
  95. StringVector_t m_directories;
  96. StringVector_t m_symdirectories;
  97. StringVector_t m_symfiles;
  98. };
  99. class Decompression_t
  100. {
  101. public:
  102. String_t m_from;
  103. String_t m_to;
  104. };
  105. typedef std::vector<Decompression_t> Decompressions_t;
  106. class Popcopy_t
  107. {
  108. public:
  109. ~Popcopy_t() { }
  110. Popcopy_t() : m_bat(false), m_copy(true)
  111. {
  112. }
  113. void Main(const StringVector_t& args);
  114. void ReadBinlist();
  115. void CreateDirectory(const std::string& partial);
  116. void CopyFile(const std::string& partial);
  117. void CopyFile(const String_t& from, const String_t& to);
  118. void DoQueuedDecompressions();
  119. void QueueDecompression(const String_t& from, const String_t& to);
  120. Binlist_t m_binlist;
  121. StringToStringMap_t m_options;
  122. String_t m_from;
  123. String_t m_fromcomp; // m_from + "\\comp"
  124. String_t m_to;
  125. String_t m_tocomp; // m_to + "\\comp"
  126. bool m_bat;
  127. bool m_copy;
  128. //
  129. // compressions are all recorded, to be done last, after all the copies
  130. //
  131. Decompressions_t m_decompressions;
  132. };
  133. String_t RemoveTrailingChars(const String_t& s, const char* set)
  134. {
  135. String_t::size_type pos = s.find_last_not_of(set);
  136. if (pos != npos)
  137. return s.substr(0, 1 + pos);
  138. return s;
  139. }
  140. String_t RemoveTrailingSlashes(const String_t& s)
  141. {
  142. return RemoveTrailingChars(s, " \\/");
  143. }
  144. String_t RemoveLastPathElement(const String_t& s)
  145. {
  146. String_t t = RemoveTrailingSlashes(s);
  147. return RemoveTrailingSlashes(t.substr(0, t.find_last_of("\\/")));
  148. }
  149. String_t RemoveTrailingWhitespace(String_t s)
  150. {
  151. return RemoveTrailingChars(s, " \r\t\n\v");
  152. }
  153. template <typename T>
  154. void SortUnique(T& t)
  155. {
  156. std::sort(t.begin(), t.end());
  157. t.resize(std::unique(t.begin(), t.end()) - t.begin());
  158. }
  159. String_t JoinPaths(const std::string& s, const std::string& t) {
  160. std::string u = s;
  161. if (u.length() == 0 || (u[u.length() - 1] != '\\' && u[u.length() - 1] != '/'))
  162. u += "\\";
  163. if (t.length() != 0 && (t[0] == '\\' || t[0] == '/'))
  164. u += t.substr(1);
  165. else
  166. u += t;
  167. //printf("%s + %s = %s\n", s.c_str(), t.c_str(), u.c_str());
  168. return u;
  169. }
  170. void Popcopy_t::ReadBinlist()
  171. {
  172. std::ifstream in(JoinPaths(m_from, "build_logs\\build.binlist").c_str());
  173. String_t line;
  174. while (std::getline(in, line))
  175. {
  176. line = RemoveTrailingWhitespace(line);
  177. line.MakeLower();
  178. // x:\binaries.x86chk\foo -> foo
  179. line = line.substr(1 + line.find_first_of("\\/"));
  180. line = line.substr(1 + line.find_first_of("\\/"));
  181. //line = line.substr(1 + line.find_first_of("\\/", line.find_first_of("\\/")));
  182. String_t::size_type lastPathSeperator = line.find_last_of("\\/");
  183. bool issyms = (line.find("symbols\\") != npos || line.find("symbols.pri\\") != npos);
  184. if (issyms)
  185. {
  186. if (lastPathSeperator != npos)
  187. {
  188. String_t dir = JoinPaths(m_to, line.substr(0, lastPathSeperator));
  189. while (dir != m_to)
  190. {
  191. m_binlist.m_directories.push_back(dir);
  192. dir = RemoveLastPathElement(dir);
  193. }
  194. }
  195. m_binlist.m_symfiles.push_back(line);
  196. }
  197. else
  198. {
  199. if (lastPathSeperator != npos)
  200. {
  201. String_t dir = JoinPaths(m_to, line.substr(0, lastPathSeperator));
  202. while (dir != m_to)
  203. {
  204. m_binlist.m_directories.push_back(dir);
  205. dir = RemoveLastPathElement(dir);
  206. }
  207. dir = JoinPaths(m_tocomp, line.substr(0, lastPathSeperator));
  208. while (dir != m_to)
  209. {
  210. m_binlist.m_directories.push_back(dir);
  211. dir = RemoveLastPathElement(dir);
  212. }
  213. }
  214. m_binlist.m_files.push_back(line);
  215. }
  216. }
  217. m_binlist.m_directories.push_back(m_to);
  218. m_binlist.m_directories.push_back(JoinPaths(m_to, "comp"));
  219. SortUnique(m_binlist.m_symfiles);
  220. SortUnique(m_binlist.m_symdirectories);
  221. SortUnique(m_binlist.m_files);
  222. SortUnique(m_binlist.m_directories);
  223. }
  224. void
  225. Popcopy_t::CreateDirectory(
  226. const std::string& full
  227. )
  228. {
  229. unsigned long Error;
  230. if (m_bat)
  231. printf("%s\n", ("mkdir " + full).c_str());
  232. else
  233. {
  234. if (!::CreateDirectory(full.c_str(), NULL)
  235. && (Error = GetLastError()) != ERROR_ALREADY_EXISTS)
  236. {
  237. printf(("CreateDirectory(" + full + ") failed, error %lu\n").c_str(), Error);
  238. }
  239. }
  240. }
  241. void
  242. Popcopy_t::QueueDecompression(
  243. const String_t& from,
  244. const String_t& to
  245. )
  246. {
  247. Decompression_t d;
  248. d.m_from = from;
  249. d.m_to = to;
  250. m_decompressions.push_back(d);
  251. }
  252. UINT
  253. CALLBACK
  254. CabinetCallback(
  255. void* Context,
  256. unsigned Notification,
  257. UINT_PTR Param1,
  258. UINT_PTR Param2
  259. )
  260. {
  261. PFILE_IN_CABINET_INFO FileInCabinetInfo;
  262. switch (Notification)
  263. {
  264. case SPFILENOTIFY_FILEINCABINET:
  265. FileInCabinetInfo = reinterpret_cast<PFILE_IN_CABINET_INFO>(Param1);
  266. strcpy(FileInCabinetInfo->FullTargetName, reinterpret_cast<const String_t*>(Context)->c_str());
  267. return FILEOP_DOIT;
  268. case SPFILENOTIFY_FILEEXTRACTED:
  269. return NO_ERROR;
  270. case SPFILENOTIFY_CABINETINFO:
  271. return NO_ERROR;
  272. case SPFILENOTIFY_NEEDNEWCABINET:
  273. return ~0u;
  274. default:
  275. return ~0u;
  276. }
  277. }
  278. void
  279. Popcopy_t::DoQueuedDecompressions(
  280. )
  281. {
  282. unsigned long Error;
  283. for (Decompressions_t::const_iterator i = m_decompressions.begin() ;
  284. i != m_decompressions.end();
  285. ++i
  286. )
  287. {
  288. if (m_bat)
  289. {
  290. printf("expand %s %s\n", i->m_from.c_str(), i->m_to.c_str());
  291. }
  292. else
  293. {
  294. if (!SetupIterateCabinet(i->m_from.c_str(), 0, CabinetCallback, const_cast<void*>(static_cast<const void*>((&i->m_to)))))
  295. {
  296. Error = GetLastError();
  297. fprintf(stderr, ("SetupIterateCabinet(" + i->m_from + ", " + i->m_to + ") failed, error %lu\n").c_str(), Error);
  298. }
  299. }
  300. }
  301. }
  302. void
  303. Popcopy_t::CopyFile(
  304. const String_t& from,
  305. const String_t& to
  306. )
  307. {
  308. unsigned long Error;
  309. if (m_copy)
  310. {
  311. if (GetFileAttributes(from.c_str()) == -1)
  312. {
  313. Error = GetLastError();
  314. if (Error == ERROR_FILE_NOT_FOUND
  315. || Error == ERROR_PATH_NOT_FOUND
  316. )
  317. {
  318. return;
  319. }
  320. fprintf(stderr, ("CopyFile(" + from + ", " + to + ") failed, error %lu\n").c_str(), Error);
  321. }
  322. if (!::CopyFile(from.c_str(), to.c_str(), FALSE))
  323. {
  324. Error = GetLastError();
  325. fprintf(stderr, ("CopyFile(" + from + ", " + to + ") failed, error %lu\n").c_str(), Error);
  326. }
  327. }
  328. }
  329. void
  330. Popcopy_t::CopyFile(
  331. const std::string& partial
  332. )
  333. {
  334. //unsigned long Error;
  335. bool comp = false;
  336. String_t fromfull = JoinPaths(m_from, partial);
  337. String_t tofull = JoinPaths(m_to, partial);
  338. String_t partialcomp = partial;
  339. // if no extension, append "._"
  340. // if extension shorter than three chars, append "_"
  341. // if extension is three or more chars, change last char to "_"
  342. std::string::size_type dot = partial.find_last_of(".");
  343. std::string::size_type sep = partial.find_last_of("\\/");
  344. if (dot == npos || (sep != npos && dot < sep))
  345. {
  346. partialcomp = partial + "._";
  347. }
  348. else if (partialcomp.length() - dot < 4)
  349. {
  350. partialcomp = partial + "_";
  351. }
  352. else
  353. {
  354. partialcomp = partial.substr(0, partial.length() - 1) + "_";
  355. }
  356. //printf("partial=%s, partialcomp=%s\n", partial.c_str(), partialcomp.c_str());
  357. //
  358. // check for the comp file
  359. //
  360. String_t fromcompfull = JoinPaths(m_fromcomp, partialcomp);
  361. String_t tocompfull;
  362. if (GetFileAttributes(fromcompfull.c_str()) != -1)
  363. {
  364. fromfull = fromcompfull;
  365. comp = true;
  366. tocompfull = JoinPaths(m_tocomp, partialcomp);
  367. }
  368. if (m_bat)
  369. {
  370. if (comp)
  371. {
  372. printf("copy %s %s\n", fromcompfull.c_str(), tocompfull.c_str());
  373. QueueDecompression(tocompfull, tofull);
  374. }
  375. else
  376. {
  377. printf("copy %s %s\n", fromfull.c_str(), tofull.c_str());
  378. }
  379. }
  380. else
  381. {
  382. if (comp)
  383. {
  384. CopyFile(fromcompfull, tocompfull);
  385. QueueDecompression(tocompfull, tofull);
  386. }
  387. else
  388. {
  389. CopyFile(fromfull, tofull);
  390. }
  391. }
  392. }
  393. void Popcopy_t::Main(
  394. const StringVector_t& args
  395. )
  396. {
  397. const String_t::size_type npos = String_t::npos;
  398. StringVector_t::const_iterator i;
  399. time_t time1;
  400. time_t time2;
  401. ::time(&time1);
  402. printf("start time %s\n", ctime(&time1));
  403. for (
  404. i = args.begin();
  405. i != args.end();
  406. ++i
  407. )
  408. {
  409. String_t arg = *i;
  410. if (arg[0] == '-' || arg[0] == '/')
  411. {
  412. arg = arg.substr(1);
  413. String_t value = "true";
  414. String_t::size_type equals;
  415. if (
  416. (arg[0] == 'n' || arg[0] == 'N')
  417. && (arg[1] == 'o' || arg[1] == 'O')
  418. )
  419. {
  420. value = "false";
  421. arg = arg.substr(2);
  422. }
  423. else if (
  424. (equals = arg.find_first_of('=')) != npos
  425. || (equals = arg.find_first_of(':')) != npos
  426. )
  427. {
  428. value = arg.substr(1 + equals);
  429. arg = arg.substr(0, equals);
  430. }
  431. m_options[arg] = value;
  432. }
  433. }
  434. m_from = RemoveTrailingSlashes(m_options["from"]);
  435. if (IsFalse(m_from) || IsTrue(m_from))
  436. {
  437. CommandLineError("missing required parameter \"from\"");
  438. }
  439. m_fromcomp = JoinPaths(m_from, "comp");
  440. m_to = RemoveTrailingSlashes(m_options["to"]);
  441. if (IsFalse(m_to) || IsTrue(m_to))
  442. {
  443. CommandLineError("missing required parameter \"to\"");
  444. }
  445. m_tocomp = JoinPaths(m_to, "comp");
  446. m_copy = !IsFalse(m_options["copy"]);
  447. ReadBinlist();
  448. m_bat = IsTrue(m_options["bat"]);
  449. if (IsFalse(m_options["symonly"]))
  450. {
  451. for (i = m_binlist.m_directories.begin() ; i != m_binlist.m_directories.end() ; ++i)
  452. this->CreateDirectory(*i);
  453. for (i = m_binlist.m_files.begin() ; i != m_binlist.m_files.end() ; ++i)
  454. this->CopyFile(*i);
  455. DoQueuedDecompressions();
  456. //
  457. // we make a bunch of extra empty comp directories, so delete any empty directories
  458. //
  459. for (i = m_binlist.m_directories.begin() ; i != m_binlist.m_directories.end() ; ++i)
  460. ::RemoveDirectory(i->c_str());
  461. }
  462. if (IsTrue(m_options["symonly"]) || IsTrue(m_options["sym"]) || IsTrue(m_options["symbols"]))
  463. {
  464. for (i = m_binlist.m_symdirectories.begin() ; i != m_binlist.m_symdirectories.end() ; ++i)
  465. this->CreateDirectory(*i);
  466. for (i = m_binlist.m_symfiles.begin() ; i != m_binlist.m_symfiles.end() ; ++i)
  467. this->CopyFile(*i);
  468. }
  469. ::time(&time2);
  470. printf("start time %s\n", ctime(&time1));
  471. printf("ending time %s\n", ctime(&time2));
  472. }
  473. int __cdecl main(int argc, char** argv)
  474. {
  475. Popcopy_t popcopy;
  476. StringVector_t args;
  477. std::copy(argv + 1, argv + argc, std::back_inserter(args));
  478. popcopy.Main(args);
  479. return 0;
  480. }