windows-nt/Source/XPSP1/NT/base/win32/fusion/tools/popcopy/popcopy.cpp
2020-09-26 16:20:57 +08:00

545 lines
13 KiB
C++

/*
Copy a build from a vbl share to the local machine, in order to
PopulateFromVBL from the local copy.
Usage:
popcopy -option
popcopy -nooption
popcopy -option:value
popcopy -option=value
Options:
-from (required)
-to (required)
-nosym (default)
-symonly
-sym
-bat (prints a .bat file instead of running commands)
-nocopy (hack so to simulate "-localuncomponly" so I can debug it)
Jay Krell
May 3, 2001
*/
#pragma warning(disable:4786) // identifier was truncated to '255' character
#include "stdinc.h"
#include <vector>
#include <map>
#include <string>
#include <iterator>
#include <stdlib.h>
#include <set>
#include <fstream>
#include <algorithm>
#include <time.h>
#include "windows.h"
#include "setupapi.h"
const std::string::size_type npos = std::string::npos;
class String_t : public std::string
//
// 1) comparison is case insensitive
// 2) MAYBE slashes sort like \1, but not currently
//
{
typedef std::string Base_t;
public:
String_t() { }
~String_t() { }
String_t(const Base_t& s) : Base_t(s) { }
String_t(const char* s) : Base_t(s) { }
void operator=(const char* s) { Base_t::operator=(s); }
void operator=(const std::string& s) { Base_t::operator=(s); }
//operator const char*() const { return c_str(); }
bool operator<(const char* t) const
{
return _stricmp(c_str(), t) < 0;
}
bool operator==(const char* t) const
{
return _stricmp(c_str(), t) == 0;
}
bool operator<(const std::string& t) const
{
return operator<(t.c_str());
}
bool operator==(const std::string& t) const
{
return operator==(t.c_str());
}
void MakeLower()
{
for (iterator i = begin() ; i != end() ; ++i)
{
*i = static_cast<char>(tolower(*i));
}
}
};
typedef std::vector<String_t> StringVector_t;
typedef std::set<String_t> StringSet_t;
typedef std::map<String_t, String_t> StringToStringMap_t;
bool IsTrue(const String_t& s)
{
return (s == "1" || s == "true" || s == "True" || s == "TRUE"); }
bool IsFalse(const String_t& s)
{
return (s == "" || s == "0" || s == "false" || s == "False" || s == "FALSE"); }
void CommandLineError(
const String_t& e
)
{
fprintf(stderr, "%s\n", e.c_str());
exit(EXIT_FAILURE);
}
class Binlist_t
{
public:
Binlist_t() { }
~Binlist_t() { }
StringVector_t m_files;
StringVector_t m_directories;
StringVector_t m_symdirectories;
StringVector_t m_symfiles;
};
class Decompression_t
{
public:
String_t m_from;
String_t m_to;
};
typedef std::vector<Decompression_t> Decompressions_t;
class Popcopy_t
{
public:
~Popcopy_t() { }
Popcopy_t() : m_bat(false), m_copy(true)
{
}
void Main(const StringVector_t& args);
void ReadBinlist();
void CreateDirectory(const std::string& partial);
void CopyFile(const std::string& partial);
void CopyFile(const String_t& from, const String_t& to);
void DoQueuedDecompressions();
void QueueDecompression(const String_t& from, const String_t& to);
Binlist_t m_binlist;
StringToStringMap_t m_options;
String_t m_from;
String_t m_fromcomp; // m_from + "\\comp"
String_t m_to;
String_t m_tocomp; // m_to + "\\comp"
bool m_bat;
bool m_copy;
//
// compressions are all recorded, to be done last, after all the copies
//
Decompressions_t m_decompressions;
};
String_t RemoveTrailingChars(const String_t& s, const char* set)
{
String_t::size_type pos = s.find_last_not_of(set);
if (pos != npos)
return s.substr(0, 1 + pos);
return s;
}
String_t RemoveTrailingSlashes(const String_t& s)
{
return RemoveTrailingChars(s, " \\/");
}
String_t RemoveLastPathElement(const String_t& s)
{
String_t t = RemoveTrailingSlashes(s);
return RemoveTrailingSlashes(t.substr(0, t.find_last_of("\\/")));
}
String_t RemoveTrailingWhitespace(String_t s)
{
return RemoveTrailingChars(s, " \r\t\n\v");
}
template <typename T>
void SortUnique(T& t)
{
std::sort(t.begin(), t.end());
t.resize(std::unique(t.begin(), t.end()) - t.begin());
}
String_t JoinPaths(const std::string& s, const std::string& t) {
std::string u = s;
if (u.length() == 0 || (u[u.length() - 1] != '\\' && u[u.length() - 1] != '/'))
u += "\\";
if (t.length() != 0 && (t[0] == '\\' || t[0] == '/'))
u += t.substr(1);
else
u += t;
//printf("%s + %s = %s\n", s.c_str(), t.c_str(), u.c_str());
return u;
}
void Popcopy_t::ReadBinlist()
{
std::ifstream in(JoinPaths(m_from, "build_logs\\build.binlist").c_str());
String_t line;
while (std::getline(in, line))
{
line = RemoveTrailingWhitespace(line);
line.MakeLower();
// x:\binaries.x86chk\foo -> foo
line = line.substr(1 + line.find_first_of("\\/"));
line = line.substr(1 + line.find_first_of("\\/"));
//line = line.substr(1 + line.find_first_of("\\/", line.find_first_of("\\/")));
String_t::size_type lastPathSeperator = line.find_last_of("\\/");
bool issyms = (line.find("symbols\\") != npos || line.find("symbols.pri\\") != npos);
if (issyms)
{
if (lastPathSeperator != npos)
{
String_t dir = JoinPaths(m_to, line.substr(0, lastPathSeperator));
while (dir != m_to)
{
m_binlist.m_directories.push_back(dir);
dir = RemoveLastPathElement(dir);
}
}
m_binlist.m_symfiles.push_back(line);
}
else
{
if (lastPathSeperator != npos)
{
String_t dir = JoinPaths(m_to, line.substr(0, lastPathSeperator));
while (dir != m_to)
{
m_binlist.m_directories.push_back(dir);
dir = RemoveLastPathElement(dir);
}
dir = JoinPaths(m_tocomp, line.substr(0, lastPathSeperator));
while (dir != m_to)
{
m_binlist.m_directories.push_back(dir);
dir = RemoveLastPathElement(dir);
}
}
m_binlist.m_files.push_back(line);
}
}
m_binlist.m_directories.push_back(m_to);
m_binlist.m_directories.push_back(JoinPaths(m_to, "comp"));
SortUnique(m_binlist.m_symfiles);
SortUnique(m_binlist.m_symdirectories);
SortUnique(m_binlist.m_files);
SortUnique(m_binlist.m_directories);
}
void
Popcopy_t::CreateDirectory(
const std::string& full
)
{
unsigned long Error;
if (m_bat)
printf("%s\n", ("mkdir " + full).c_str());
else
{
if (!::CreateDirectory(full.c_str(), NULL)
&& (Error = GetLastError()) != ERROR_ALREADY_EXISTS)
{
printf(("CreateDirectory(" + full + ") failed, error %lu\n").c_str(), Error);
}
}
}
void
Popcopy_t::QueueDecompression(
const String_t& from,
const String_t& to
)
{
Decompression_t d;
d.m_from = from;
d.m_to = to;
m_decompressions.push_back(d);
}
UINT
CALLBACK
CabinetCallback(
void* Context,
unsigned Notification,
UINT Param1,
UINT Param2
)
{
PFILE_IN_CABINET_INFO FileInCabinetInfo;
switch (Notification)
{
case SPFILENOTIFY_FILEINCABINET:
FileInCabinetInfo = reinterpret_cast<PFILE_IN_CABINET_INFO>(Param1);
strcpy(FileInCabinetInfo->FullTargetName, reinterpret_cast<const String_t*>(Context)->c_str());
return FILEOP_DOIT;
case SPFILENOTIFY_FILEEXTRACTED:
return NO_ERROR;
case SPFILENOTIFY_CABINETINFO:
return NO_ERROR;
case SPFILENOTIFY_NEEDNEWCABINET:
return ~0u;
default:
return ~0u;
}
}
void
Popcopy_t::DoQueuedDecompressions(
)
{
unsigned long Error;
for (Decompressions_t::const_iterator i = m_decompressions.begin() ;
i != m_decompressions.end();
++i
)
{
if (m_bat)
{
printf("expand %s %s\n", i->m_from.c_str(), i->m_to.c_str());
}
else
{
if (!SetupIterateCabinet(i->m_from.c_str(), 0, CabinetCallback, const_cast<void*>(static_cast<const void*>((&i->m_to)))))
{
Error = GetLastError();
fprintf(stderr, ("SetupIterateCabinet(" + i->m_from + ", " + i->m_to + ") failed, error %lu\n").c_str(), Error);
}
}
}
}
void
Popcopy_t::CopyFile(
const String_t& from,
const String_t& to
)
{
unsigned long Error;
if (m_copy)
{
if (GetFileAttributes(from.c_str()) == -1)
{
Error = GetLastError();
if (Error == ERROR_FILE_NOT_FOUND
|| Error == ERROR_PATH_NOT_FOUND
)
{
return;
}
fprintf(stderr, ("CopyFile(" + from + ", " + to + ") failed, error %lu\n").c_str(), Error);
}
if (!::CopyFile(from.c_str(), to.c_str(), FALSE))
{
Error = GetLastError();
fprintf(stderr, ("CopyFile(" + from + ", " + to + ") failed, error %lu\n").c_str(), Error);
}
}
}
void
Popcopy_t::CopyFile(
const std::string& partial
)
{
//unsigned long Error;
bool comp = false;
String_t fromfull = JoinPaths(m_from, partial);
String_t tofull = JoinPaths(m_to, partial);
String_t partialcomp = partial;
// if no extension, append "._"
// if extension shorter than three chars, append "_"
// if extension is three or more chars, change last char to "_"
std::string::size_type dot = partial.find_last_of(".");
std::string::size_type sep = partial.find_last_of("\\/");
if (dot == npos || (sep != npos && dot < sep))
{
partialcomp = partial + "._";
}
else if (partialcomp.length() - dot < 4)
{
partialcomp = partial + "_";
}
else
{
partialcomp = partial.substr(0, partial.length() - 1) + "_";
}
//printf("partial=%s, partialcomp=%s\n", partial.c_str(), partialcomp.c_str());
//
// check for the comp file
//
String_t fromcompfull = JoinPaths(m_fromcomp, partialcomp);
String_t tocompfull;
if (GetFileAttributes(fromcompfull.c_str()) != -1)
{
fromfull = fromcompfull;
comp = true;
tocompfull = JoinPaths(m_tocomp, partialcomp);
}
if (m_bat)
{
if (comp)
{
printf("copy %s %s\n", fromcompfull.c_str(), tocompfull.c_str());
QueueDecompression(tocompfull, tofull);
}
else
{
printf("copy %s %s\n", fromfull.c_str(), tofull.c_str());
}
}
else
{
if (comp)
{
CopyFile(fromcompfull, tocompfull);
QueueDecompression(tocompfull, tofull);
}
else
{
CopyFile(fromfull, tofull);
}
}
}
void Popcopy_t::Main(
const StringVector_t& args
)
{
const String_t::size_type npos = String_t::npos;
StringVector_t::const_iterator i;
time_t time1;
time_t time2;
::time(&time1);
printf("start time %s\n", ctime(&time1));
for (
i = args.begin();
i != args.end();
++i
)
{
String_t arg = *i;
if (arg[0] == '-' || arg[0] == '/')
{
arg = arg.substr(1);
String_t value = "true";
String_t::size_type equals;
if (
(arg[0] == 'n' || arg[0] == 'N')
&& (arg[1] == 'o' || arg[1] == 'O')
)
{
value = "false";
arg = arg.substr(2);
}
else if (
(equals = arg.find_first_of('=')) != npos
|| (equals = arg.find_first_of(':')) != npos
)
{
value = arg.substr(1 + equals);
arg = arg.substr(0, equals);
}
m_options[arg] = value;
}
}
m_from = RemoveTrailingSlashes(m_options["from"]);
if (IsFalse(m_from) || IsTrue(m_from))
{
CommandLineError("missing required parameter \"from\"");
}
m_fromcomp = JoinPaths(m_from, "comp");
m_to = RemoveTrailingSlashes(m_options["to"]);
if (IsFalse(m_to) || IsTrue(m_to))
{
CommandLineError("missing required parameter \"to\"");
}
m_tocomp = JoinPaths(m_to, "comp");
m_copy = !IsFalse(m_options["copy"]);
ReadBinlist();
m_bat = IsTrue(m_options["bat"]);
if (IsFalse(m_options["symonly"]))
{
for (i = m_binlist.m_directories.begin() ; i != m_binlist.m_directories.end() ; ++i)
this->CreateDirectory(*i);
for (i = m_binlist.m_files.begin() ; i != m_binlist.m_files.end() ; ++i)
this->CopyFile(*i);
DoQueuedDecompressions();
//
// we make a bunch of extra empty comp directories, so delete any empty directories
//
for (i = m_binlist.m_directories.begin() ; i != m_binlist.m_directories.end() ; ++i)
::RemoveDirectory(i->c_str());
}
if (IsTrue(m_options["symonly"]) || IsTrue(m_options["sym"]) || IsTrue(m_options["symbols"]))
{
for (i = m_binlist.m_symdirectories.begin() ; i != m_binlist.m_symdirectories.end() ; ++i)
this->CreateDirectory(*i);
for (i = m_binlist.m_symfiles.begin() ; i != m_binlist.m_symfiles.end() ; ++i)
this->CopyFile(*i);
}
::time(&time2);
printf("start time %s\n", ctime(&time1));
printf("ending time %s\n", ctime(&time2));
}
int __cdecl main(int argc, char** argv)
{
Popcopy_t popcopy;
StringVector_t args;
std::copy(argv + 1, argv + argc, std::back_inserter(args));
popcopy.Main(args);
return 0;
}