summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2005-01-11 03:59:42 +0000
committerMichi Henning <michi@zeroc.com>2005-01-11 03:59:42 +0000
commitbfdd46fc78552716f25900de5b75a6aff79c6d7c (patch)
treeb0078934828f0c08be6d5f2bf12757e1010f5ed1 /cpp/src
parentCommented out the delete[] args calls again -- I couldn't reproduce a (diff)
downloadice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.tar.bz2
ice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.tar.xz
ice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.zip
Minor refactoring of IcePatch2.
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/IcePatch2/Calc.cpp71
-rw-r--r--cpp/src/IcePatch2/Client.cpp23
-rwxr-xr-xcpp/src/IcePatch2/ClientUtil.cpp89
-rw-r--r--cpp/src/IcePatch2/FileServerI.cpp24
-rw-r--r--cpp/src/IcePatch2/FileServerI.h5
-rw-r--r--cpp/src/IcePatch2/Server.cpp85
-rw-r--r--cpp/src/IcePatch2/Util.cpp268
7 files changed, 338 insertions, 227 deletions
diff --git a/cpp/src/IcePatch2/Calc.cpp b/cpp/src/IcePatch2/Calc.cpp
index 1621c63f196..5d8f7aeefce 100644
--- a/cpp/src/IcePatch2/Calc.cpp
+++ b/cpp/src/IcePatch2/Calc.cpp
@@ -174,68 +174,35 @@ main(int argc, char* argv[])
usage(argv[0]);
return EXIT_FAILURE;
}
- dataDir = normalize(args[0]);
-
- for(vector<string>::size_type i = 1; i < args.size(); ++i)
- {
- fileSeq.push_back(normalize(args[i]));
- }
try
{
- StringSeq::iterator p;
- string absDataDir = dataDir;
-
-#ifdef _WIN32
- char cwd[_MAX_PATH];
- if(_getcwd(cwd, _MAX_PATH) == NULL)
+ //
+ // Make working directory the data directory *before* calling normalize() for
+ // for the first time (because normalize caches the current working directory).
+ //
+ if(chdir(args[0].c_str()) != 0)
{
- throw "cannot get the current directory:\n" + lastError();
+ string msg = "cannot change working directory to `" + args[0] + "': " + lastError();
+ throw msg;
}
-
- if(absDataDir[0] != '/' && !(absDataDir.size() > 1 && isalpha(absDataDir[0]) && absDataDir[1] == ':'))
- {
- absDataDir = string(cwd) + '/' + absDataDir;
- }
-
- for(p = fileSeq.begin(); p != fileSeq.end(); ++p)
- {
- if((*p)[0] != '/' && !(p->size() > 1 && isalpha((*p)[0]) && (*p)[1] == ':'))
- {
- *p = string(cwd) + '/' + *p;
- }
- }
-#else
- char cwd[PATH_MAX];
- if(getcwd(cwd, PATH_MAX) == NULL)
- {
- throw "cannot get the current directory:\n" + lastError();
- }
-
- if(absDataDir[0] != '/')
- {
- absDataDir = string(cwd) + '/' + absDataDir;
- }
-
- for(p = fileSeq.begin(); p != fileSeq.end(); ++p)
+ dataDir = normalize(".");
+ string dataDirWithSlash = dataDir + "/";
+
+ for(vector<string>::size_type i = 1; i < args.size(); ++i)
{
- if((*p)[0] != '/')
- {
- *p = string(cwd) + '/' + *p;
- }
+ fileSeq.push_back(normalize(args[i]));
}
-#endif
- string absDataDirWithSlash = absDataDir + '/';
-
+ StringSeq::iterator p;
for(p = fileSeq.begin(); p != fileSeq.end(); ++p)
{
- if(p->compare(0, absDataDirWithSlash.size(), absDataDirWithSlash) != 0)
+ if(p->compare(0, dataDirWithSlash.size(), dataDirWithSlash) != 0)
{
throw "`" + *p + "' is not a path in `" + dataDir + "'";
}
- p->erase(0, absDataDirWithSlash.size());
+ p->erase(0, dataDirWithSlash.size());
}
FileInfoSeq infoSeq;
@@ -243,21 +210,21 @@ main(int argc, char* argv[])
if(fileSeq.empty())
{
CalcCB calcCB;
- if(!getFileInfoSeq(absDataDir, compress, verbose ? &calcCB : 0, infoSeq))
+ if(!getFileInfoSeq(".", compress, verbose ? &calcCB : 0, infoSeq))
{
return EXIT_FAILURE;
}
}
else
{
- loadFileInfoSeq(absDataDir, infoSeq);
+ loadFileInfoSeq(".", infoSeq);
for(p = fileSeq.begin(); p != fileSeq.end(); ++p)
{
FileInfoSeq partialInfoSeq;
CalcCB calcCB;
- if(!getFileInfoSeqSubDir(absDataDir, *p, compress, verbose ? &calcCB : 0, partialInfoSeq))
+ if(!getFileInfoSeq(*p, compress, verbose ? &calcCB : 0, partialInfoSeq))
{
return EXIT_FAILURE;
}
@@ -312,7 +279,7 @@ main(int argc, char* argv[])
}
}
- saveFileInfoSeq(absDataDir, infoSeq);
+ saveFileInfoSeq(dataDir, infoSeq);
}
catch(const string& ex)
{
diff --git a/cpp/src/IcePatch2/Client.cpp b/cpp/src/IcePatch2/Client.cpp
index 8c9581061f2..ce6752b215b 100644
--- a/cpp/src/IcePatch2/Client.cpp
+++ b/cpp/src/IcePatch2/Client.cpp
@@ -14,6 +14,7 @@
#ifdef _WIN32
# include <conio.h>
+# include <direct.h>
#else
# include <fcntl.h>
# include <termios.h>
@@ -253,11 +254,25 @@ Client::run(int argc, char* argv[])
usage(argv[0]);
return EXIT_FAILURE;
}
- if(args.size() == 1)
+ if(args.empty())
{
- properties->setProperty("IcePatch2.Directory", args[0]);
+ cerr << argv[0] << ": no data directory specified" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ //
+ // Make working directory the data directory *before* calling normalize() for
+ // for the first time (because normalize caches the current working directory).
+ //
+ if(chdir(args[0].c_str()) != 0)
+ {
+ string msg = "cannot change working directory to `" + args[0] + "': " + lastError();
+ throw msg;
}
+ properties->setProperty("IcePatch2.Directory", normalize("."));
+
bool aborted = false;
try
@@ -269,7 +284,7 @@ Client::run(int argc, char* argv[])
if(!aborted)
{
- aborted = !patcher->patch("");
+ aborted = !patcher->patch(".");
}
if(!aborted)
@@ -303,7 +318,7 @@ Client::usage(const string& appName)
"-v, --version Display the Ice version.\n"
"-t, --thorough Recalculate all checksums.";
- cerr << "Usage: " << appName << " [options] [DIR]" << endl;
+ cerr << "Usage: " << appName << " [options] DIR" << endl;
cerr << options << endl;
}
diff --git a/cpp/src/IcePatch2/ClientUtil.cpp b/cpp/src/IcePatch2/ClientUtil.cpp
index 99e2452b2f0..4dc6c05fa6f 100755
--- a/cpp/src/IcePatch2/ClientUtil.cpp
+++ b/cpp/src/IcePatch2/ClientUtil.cpp
@@ -114,8 +114,8 @@ public:
try
{
- decompressFile(_dataDir + '/' + info.path);
- remove(_dataDir + '/' + info.path + ".bz2");
+ decompressFile(info.path);
+ remove(info.path + ".bz2");
}
catch(const string& ex)
{
@@ -157,30 +157,6 @@ IcePatch2::Patcher::Patcher(const CommunicatorPtr& communicator, const PatcherFe
const_cast<Int&>(_chunkSize) = 1;
}
-#ifdef _WIN32
- if(_dataDir[0] != '/' && !(_dataDir.size() > 1 && isalpha(_dataDir[0]) && _dataDir[1] == ':'))
- {
- char cwd[_MAX_PATH];
- if(_getcwd(cwd, _MAX_PATH) == NULL)
- {
- throw "cannot get the current directory:\n" + lastError();
- }
-
- const_cast<string&>(_dataDir) = string(cwd) + '/' + _dataDir;
- }
-#else
- if(_dataDir[0] != '/')
- {
- char cwd[PATH_MAX];
- if(getcwd(cwd, PATH_MAX) == NULL)
- {
- throw "cannot get the current directory:\n" + lastError();
- }
-
- const_cast<string&>(_dataDir) = string(cwd) + '/' + _dataDir;
- }
-#endif
-
PropertiesPtr properties = communicator->getProperties();
const char* endpointsProperty = "IcePatch2.Endpoints";
@@ -238,17 +214,17 @@ private:
const PatcherFeedbackPtr _feedback;
};
-class AMIGetFileInfo1Seq : public AMI_FileServer_getFileInfo1Seq, public IceUtil::Monitor<IceUtil::Mutex>
+class AMIGetFileInfoSeq : public AMI_FileServer_getFileInfoSeq, public IceUtil::Monitor<IceUtil::Mutex>
{
public:
- AMIGetFileInfo1Seq() :
+ AMIGetFileInfoSeq() :
_done(false)
{
}
FileInfoSeq
- getFileInfo1Seq()
+ getFileInfoSeq()
{
IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this);
@@ -296,7 +272,7 @@ private:
auto_ptr<Exception> _exception;
};
-typedef IceUtil::Handle<AMIGetFileInfo1Seq> AMIGetFileInfo1SeqPtr;
+typedef IceUtil::Handle<AMIGetFileInfoSeq> AMIGetFileInfoSeqPtr;
bool
IcePatch2::Patcher::prepare()
@@ -329,7 +305,7 @@ IcePatch2::Patcher::prepare()
}
PatcherGetFileInfoSeqCB cb(_feedback);
- if(!getFileInfoSeq(_dataDir, 0, &cb, _localFiles))
+ if(!getFileInfoSeq(".", 0, &cb, _localFiles))
{
return false;
}
@@ -352,25 +328,25 @@ IcePatch2::Patcher::prepare()
return false;
}
- ByteSeqSeq checksum0Seq = _serverCompress->getChecksum0Seq();
- if(checksum0Seq.size() != 256)
+ ByteSeqSeq checksumSeq = _serverCompress->getChecksumSeq();
+ if(checksumSeq.size() != 256)
{
throw string("server returned illegal value");
}
- AMIGetFileInfo1SeqPtr curCB;
- AMIGetFileInfo1SeqPtr nxtCB;
+ AMIGetFileInfoSeqPtr curCB;
+ AMIGetFileInfoSeqPtr nxtCB;
for(int node0 = 0; node0 < 256; ++node0)
{
- if(tree0.nodes[node0].checksum != checksum0Seq[node0])
+ if(tree0.nodes[node0].checksum != checksumSeq[node0])
{
if(!curCB)
{
assert(!nxtCB);
- curCB = new AMIGetFileInfo1Seq;
- nxtCB = new AMIGetFileInfo1Seq;
- _serverCompress->getFileInfo1Seq_async(curCB, node0);
+ curCB = new AMIGetFileInfoSeq;
+ nxtCB = new AMIGetFileInfoSeq;
+ _serverCompress->getFileInfoSeq_async(curCB, node0);
}
else
{
@@ -384,14 +360,14 @@ IcePatch2::Patcher::prepare()
{
++node0Nxt;
}
- while(node0Nxt < 256 && tree0.nodes[node0Nxt].checksum == checksum0Seq[node0Nxt]);
+ while(node0Nxt < 256 && tree0.nodes[node0Nxt].checksum == checksumSeq[node0Nxt]);
if(node0Nxt < 256)
{
- _serverNoCompress->getFileInfo1Seq_async(nxtCB, node0Nxt);
+ _serverNoCompress->getFileInfoSeq_async(nxtCB, node0Nxt);
}
- FileInfoSeq files = curCB->getFileInfo1Seq();
+ FileInfoSeq files = curCB->getFileInfoSeq();
sort(files.begin(), files.end(), FileInfoLess());
files.erase(unique(files.begin(), files.end(), FileInfoEqual()), files.end());
@@ -423,10 +399,19 @@ IcePatch2::Patcher::prepare()
}
}
- sort(_removeFiles.begin(), _removeFiles.end(), FileInfoLess());
sort(_updateFiles.begin(), _updateFiles.end(), FileInfoLess());
+ sort(_removeFiles.begin(), _removeFiles.end(), FileInfoLess());
+
+ //
+ // Remove the data dir itself from the list of files to be removed.
+ //
+ FileInfo fi;
+ fi.path = _dataDir;
+ pair<FileInfoSeq::iterator, FileInfoSeq::iterator> p
+ = equal_range(_removeFiles.begin(), _removeFiles.end(), fi, PathLess());
+ _removeFiles.erase(p.first, p.second);
- string pathLog = _dataDir + ".log";
+ string pathLog = _dataDir + "/" + logFile;
_log.open(pathLog.c_str());
if(!_log)
{
@@ -441,7 +426,7 @@ IcePatch2::Patcher::patch(const string& d)
{
string dir = normalize(d);
- if(dir.empty() || dir == ".")
+ if(dir == _dataDir)
{
if(!_removeFiles.empty())
{
@@ -533,7 +518,7 @@ IcePatch2::Patcher::removeFiles(const FileInfoSeq& files)
{
try
{
- remove(_dataDir + '/' + p->path);
+ remove(p->path);
_log << '-' << *p << endl;
}
catch(...)
@@ -682,7 +667,7 @@ IcePatch2::Patcher::updateFilesInternal(const FileInfoSeq& files, const Decompre
{
if(p->size < 0) // Directory?
{
- createDirectoryRecursive(_dataDir + '/' + p->path);
+ createDirectoryRecursive(p->path);
_log << '+' << *p << endl;
}
else // Regular file.
@@ -694,18 +679,14 @@ IcePatch2::Patcher::updateFilesInternal(const FileInfoSeq& files, const Decompre
if(p->size == 0)
{
- string path = _dataDir + '/' + p->path;
- ofstream file(path.c_str(), ios::binary);
+ ofstream file(p->path.c_str(), ios::binary);
}
else
{
- string pathBZ2 = _dataDir + '/' + p->path + ".bz2";
+ string pathBZ2 = p->path + ".bz2";
string dir = getDirname(pathBZ2);
- if(!dir.empty())
- {
- createDirectoryRecursive(dir);
- }
+ createDirectoryRecursive(dir);
try
{
diff --git a/cpp/src/IcePatch2/FileServerI.cpp b/cpp/src/IcePatch2/FileServerI.cpp
index 519e00477d7..53a314c1214 100644
--- a/cpp/src/IcePatch2/FileServerI.cpp
+++ b/cpp/src/IcePatch2/FileServerI.cpp
@@ -23,31 +23,32 @@ using namespace Ice;
using namespace IcePatch2;
IcePatch2::FileServerI::FileServerI(const std::string& dataDir, const FileInfoSeq& infoSeq) :
- _dataDir(dataDir)
+ _dataDir(normalize(dataDir)),
+ _dataDirWithSlash(_dataDir + "/")
{
FileTree0& tree0 = const_cast<FileTree0&>(_tree0);
getFileTree0(infoSeq, tree0);
}
FileInfoSeq
-IcePatch2::FileServerI::getFileInfo1Seq(Int node0, const Current&) const
+IcePatch2::FileServerI::getFileInfoSeq(Int node, const Current&) const
{
- if(node0 < 0 || node0 > 255)
+ if(node < 0 || node > 255)
{
throw NodeOutOfRangeException();
}
- return _tree0.nodes[node0].files;
+ return _tree0.nodes[node].files;
}
ByteSeqSeq
-IcePatch2::FileServerI::getChecksum0Seq(const Current&) const
+IcePatch2::FileServerI::getChecksumSeq(const Current&) const
{
ByteSeqSeq checksums(256);
- for(int node0 = 0; node0 < 256; ++node0)
+ for(int node = 0; node < 256; ++node)
{
- checksums[node0] = _tree0.nodes[node0].checksum;
+ checksums[node] = _tree0.nodes[node].checksum;
}
return checksums;
@@ -62,8 +63,13 @@ IcePatch2::FileServerI::getChecksum(const Current&) const
ByteSeq
IcePatch2::FileServerI::getFileCompressed(const string& pa, Int pos, Int num, const Current&) const
{
- string path = normalize(_dataDir + '/' + pa);
- path += ".bz2";
+ string path = normalize(pa) + ".bz2";
+ if(path.compare(0, _dataDirWithSlash.size(), _dataDirWithSlash) != 0)
+ {
+ FileAccessException ex;
+ ex.reason = "`" + pa + "' is not a path in `" + _dataDir + "'";
+ throw ex;
+ }
if(num <= 0 || pos < 0)
{
diff --git a/cpp/src/IcePatch2/FileServerI.h b/cpp/src/IcePatch2/FileServerI.h
index defdb0a282a..6a22bfcb674 100644
--- a/cpp/src/IcePatch2/FileServerI.h
+++ b/cpp/src/IcePatch2/FileServerI.h
@@ -22,9 +22,9 @@ public:
FileServerI(const std::string&, const FileInfoSeq&);
- FileInfoSeq getFileInfo1Seq(Ice::Int, const Ice::Current&) const;
+ FileInfoSeq getFileInfoSeq(Ice::Int, const Ice::Current&) const;
- ByteSeqSeq getChecksum0Seq(const Ice::Current&) const;
+ ByteSeqSeq getChecksumSeq(const Ice::Current&) const;
Ice::ByteSeq getChecksum(const Ice::Current&) const;
@@ -33,6 +33,7 @@ public:
private:
const std::string _dataDir;
+ const std::string _dataDirWithSlash;
const FileTree0 _tree0;
};
diff --git a/cpp/src/IcePatch2/Server.cpp b/cpp/src/IcePatch2/Server.cpp
index 8962389cace..52bb0559243 100644
--- a/cpp/src/IcePatch2/Server.cpp
+++ b/cpp/src/IcePatch2/Server.cpp
@@ -104,14 +104,14 @@ IcePatch2::PatcherService::start(int argc, char* argv[])
usage(argv[0]);
return false;
}
- if(args.size() == 1)
- {
- dataDir = args[0];
- }
PropertiesPtr properties = communicator()->getProperties();
- if(dataDir.empty())
+ if(!args.empty())
+ {
+ dataDir = args[0];
+ }
+ else
{
dataDir = properties->getProperty("IcePatch2.Directory");
if(dataDir.empty())
@@ -126,23 +126,16 @@ IcePatch2::PatcherService::start(int argc, char* argv[])
try
{
-#ifdef _WIN32
- if(dataDir[0] != '/' && !(dataDir.size() > 1 && isalpha(dataDir[0]) && dataDir[1] == ':'))
+ //
+ // Make working directory the data directory *before* calling normalize() for
+ // for the first time (because normalize caches the current working directory).
+ //
+ if(chdir(dataDir.c_str()) != 0)
{
- char cwd[_MAX_PATH];
- if(_getcwd(cwd, _MAX_PATH) == NULL)
-#else
- if(dataDir[0] != '/')
- {
- char cwd[PATH_MAX];
- if(getcwd(cwd, PATH_MAX) == NULL)
-#endif
- {
- throw "cannot get the current directory:\n" + lastError();
- }
-
- dataDir = string(cwd) + '/' + dataDir;
+ string msg = "cannot change working directory to `" + dataDir + "': " + lastError();
+ throw msg;
}
+ dataDir = normalize(".");
loadFileInfoSeq(dataDir, infoSeq);
}
@@ -240,7 +233,8 @@ IcePatch2::PatcherService::usage(const string& appName)
"\n"
"--daemon Run as a daemon.\n"
"--noclose Do not close open file descriptors.\n"
- "--nochdir Do not change the current working directory."
+
+ // --nochdir is intentionally not shown here. (See the comment in main().)
);
#endif
cerr << "Usage: " << appName << " [options] [DIR]" << endl;
@@ -251,5 +245,52 @@ int
main(int argc, char* argv[])
{
IcePatch2::PatcherService svc;
- return svc.main(argc, argv);
+ int status = EXIT_FAILURE;
+
+#ifdef _WIN32
+ status = svc.main(argc, argv);
+#else
+ //
+ // For UNIX, force --nochdir option, so the service isn't started with /
+ // as the working directory. That way, if the data directory is
+ // specified as a relative path, we don't misinterpret that path.
+ //
+ char** v = new char*[argc + 2];
+ char** vsave = new char*[argc + 2]; // We need to keep a copy of the vector because svc.main modifies argv.
+
+ v[0] = new char[strlen(argv[0]) + 1];
+ strcpy(v[0], argv[0]);
+ vsave[0] = v[0];
+
+ v[1] = new char[sizeof("--nochdir")];
+ strcpy(v[1], "--nochdir");
+ vsave[1] = v[1];
+
+ int i;
+ for(i = 1; i < argc; ++i)
+ {
+ v[i + 1] = new char[strlen(argv[i]) + 1];
+ strcpy(v[i + 1], argv[i]);
+ vsave[i + 1] = v[i + 1];
+ }
+ v[argc + 1] = 0;
+
+ try
+ {
+ status = svc.main(argc + 1, v);
+ }
+ catch(...)
+ {
+ // Ignore exceptions -- the only thing left to do is to free memory.
+ }
+
+ for(i = 0; i < argc + 1; ++i)
+ {
+ delete[] vsave[i];
+ }
+ delete[] v;
+ delete[] vsave;
+#endif
+
+ return status;
}
diff --git a/cpp/src/IcePatch2/Util.cpp b/cpp/src/IcePatch2/Util.cpp
index e37a240537c..25efa90eebb 100644
--- a/cpp/src/IcePatch2/Util.cpp
+++ b/cpp/src/IcePatch2/Util.cpp
@@ -100,6 +100,9 @@ using namespace std;
using namespace Ice;
using namespace IcePatch2;
+const char* IcePatch2::checksumFile = "IcePatch2.sum";
+const char* IcePatch2::logFile = "IcePatch2.log";
+
string
IcePatch2::lastError()
{
@@ -213,11 +216,21 @@ IcePatch2::stringToBytes(const string& str)
string
IcePatch2::normalize(const string& path)
{
- string result = path;
+ static string cwd;
+ static string drive;
+ string result = path;
string::size_type pos;
+ if(result.empty())
+ {
+ throw "Invalid empty path";
+ }
+
#ifdef _WIN32
+ //
+ // Turn backslashes into forward slashes.
+ //
for(pos = 0; pos < result.size(); ++pos)
{
if(result[pos] == '\\')
@@ -227,66 +240,147 @@ IcePatch2::normalize(const string& path)
}
#endif
+ //
+ // Get current working directory the first time we come through here.
+ //
+ {
+ static bool cwdDone = false;
+ static IceUtil::StaticMutex m = ICE_STATIC_MUTEX_INITIALIZER;
+
+ IceUtil::StaticMutex::Lock sync(m);
+
+ if(!cwdDone)
+ {
+#ifdef _WIN32
+ char buf[MAX_PATH];
+ if(_getcwd(buf, sizeof(buf)) == NULL)
+#else
+ char buf[PATH_MAX];
+ if(getcwd(buf, sizeof(buf)) == NULL)
+#endif
+ {
+ throw "cannot get the current directory:\n" + lastError();
+ }
+#ifdef _WIN32
+ for(pos = 0; buf[pos] != '\0'; ++pos)
+ {
+ if(buf[pos] == '\\')
+ {
+ buf[pos] = '/';
+ }
+ }
+#endif
+ cwd = buf;
+ drive = cwd.substr(0, 2);
+ cwdDone = true;
+ }
+ }
+
+ //
+ // Create absolute path. For Windows, we make sure that there always is a drive letter.
+ // Otherwise, if the data directory is specified as C:/, and we ask for a file /a, we
+ // end up with C:/a. This avoids erroneously concluding that C:/a is not the same file as /a.
+ //
+ bool isAbsolute;
+#ifdef _WIN32
+ isAbsolute = result[0] == '/' || (result.size() > 1 && isalpha(result[0]) && result[1] == ':');
+ if(result[0] == '/')
+ {
+ result = drive + result;
+ }
+#else
+ isAbsolute = result[0] == '/';
+#endif
+ if(!isAbsolute)
+ {
+ result = cwd + "/" + result;
+ }
+
+ //
+ // Get rid of multiple adjacent slashes.
+ //
pos = 0;
while((pos = result.find("//", pos)) != string::npos)
{
result.erase(pos, 1);
}
+ //
+ // Split out the path components and put them into a vector.
+ //
+#ifdef _WIN32
+ pos = 2; // Slash follows the drive letter and colon.
+#else
pos = 0;
- while((pos = result.find("/./", pos)) != string::npos)
+#endif
+ vector<string> vec;
+ while(pos != string::npos)
{
- result.erase(pos, 2);
- }
+ string::size_type end = result.find('/', pos + 1);
+ string component;
+ if(end != string::npos)
+ {
+ component = result.substr(pos + 1, end - (pos + 1));
+ }
+ else
+ {
+ component = result.substr(pos + 1);
+ }
- if(result.substr(0, 2) == "./")
- {
- result.erase(0, 2);
- }
+ if(component.empty())
+ {
+ ; // Ignore empty component caused by trailing slash in original path.
+ }
+ else if(component == ".")
+ {
+ ; // Ignore '.'
+ }
+ else if(component == "..")
+ {
+ if(!vec.empty())
+ {
+ vec.erase(vec.end() - 1); // Jump up one level, except at the root.
+ }
+ }
+ else
+ {
+ vec.push_back(component);
+ }
- if(result.size() >= 2 && result.substr(result.size() - 2, 2) == "/.")
- {
- result.erase(result.size() - 2, 2);
+ pos = end;
}
- if(result.size() >= 1 && result[result.size() - 1] == '/')
+#ifdef _WIN32
+ result = drive;
+#else
+ result.clear();
+#endif
+
+ for(vector<string>::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
- result.erase(result.size() - 1);
+ result += "/" + *i;
}
-
return result;
}
string
IcePatch2::getSuffix(const string& pa)
{
- const string path = normalize(pa);
-
- string::size_type pos = path.rfind('.');
- if(pos == string::npos)
- {
- return string();
- }
- else
- {
- return path.substr(pos + 1);
- }
+ const string name = getBasename(pa);
+ string::size_type pos = name.rfind('.'); // '.' must appear in final path component.
+ return pos == string::npos ? string() : name.substr(pos + 1);
}
string
IcePatch2::getWithoutSuffix(const string& pa)
{
const string path = normalize(pa);
-
- string::size_type pos = path.rfind('.');
- if(pos == string::npos)
- {
- return path;
- }
- else
+ if(getBasename(pa).rfind('.') == string::npos) // '.' must appear in final path component.
{
- return path.substr(0, pos);
+ return path;
}
+ string::size_type pos = path.rfind('.');
+ return path.substr(0, pos);
}
bool
@@ -299,36 +393,52 @@ IcePatch2::ignoreSuffix(const string& path)
|| suffix == "bz2temp";
}
+static bool
+isRoot(const string& pa)
+{
+#ifdef _WIN32
+ if(pa.size() == 3 && isalpha(pa[0]) && pa[1] == ':' && pa[2] == '/')
+ {
+ return true;
+ }
+#endif
+ return pa == "/";
+}
+
string
IcePatch2::getBasename(const string& pa)
{
const string path = normalize(pa);
-
- string::size_type pos = path.rfind('/');
- if(pos == string::npos)
+ if(isRoot(path))
{
- return path;
- }
- else
- {
- return path.substr(pos + 1);
+ return path;
}
+ string::size_type pos = path.rfind('/');
+ return path.substr(pos + 1);
}
string
IcePatch2::getDirname(const string& pa)
{
- const string path = normalize(pa);
-
+ string path = normalize(pa);
+ if(isRoot(path))
+ {
+ return path;
+ }
string::size_type pos = path.rfind('/');
- if(pos == string::npos)
+ path = path.substr(0, pos);
+#ifdef _WIN32
+ if(path.size() == 2 && isalpha(path[0]) && path[1] == ':')
{
- return string();
+ return path + "/";
}
- else
+#else
+ if(path.isEmpty())
{
- return path.substr(0, pos);
+ return "/";
}
+#endif
+ return path;
}
void
@@ -513,7 +623,7 @@ IcePatch2::createDirectoryRecursive(const string& pa)
const string path = normalize(pa);
string dir = getDirname(path);
- if(!dir.empty())
+ if(!isRoot(dir))
{
createDirectoryRecursive(dir);
}
@@ -668,10 +778,13 @@ IcePatch2::decompressFile(const string& pa)
}
static bool
-getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, GetFileInfoSeqCB* cb,
- FileInfoSeq& infoSeq)
+getFileInfoSeqInt(const string& path, int compress, GetFileInfoSeqCB* cb, FileInfoSeq& infoSeq)
{
- const string path = basePath + '/' + relPath;
+ string basename = getBasename(path);
+ if(basename == checksumFile || basename == logFile) // Don't transmit these.
+ {
+ return true;
+ }
if(ignoreSuffix(path))
{
@@ -679,7 +792,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
if(ignoreSuffix(pathWithoutSuffix))
{
- if(cb && !cb->remove(relPath))
+ if(cb && !cb->remove(path))
{
return false;
}
@@ -693,7 +806,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
{
if(errno == ENOENT)
{
- if(cb && !cb->remove(relPath))
+ if(cb && !cb->remove(path))
{
return false;
}
@@ -707,7 +820,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
}
else if(buf.st_size == 0)
{
- if(cb && !cb->remove(relPath))
+ if(cb && !cb->remove(path))
{
return false;
}
@@ -724,14 +837,14 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
throw "cannot stat `" + path + "':\n" + lastError();
}
+ FileInfo info;
+ info.path = path;
if(S_ISDIR(buf.st_mode))
{
- FileInfo info;
- info.path = relPath;
info.size = -1;
- ByteSeq bytes(relPath.size());
- copy(relPath.begin(), relPath.end(), bytes.begin());
+ ByteSeq bytes(path.size());
+ copy(path.begin(), path.end(), bytes.begin());
ByteSeq bytesSHA(20);
if(!bytes.empty())
@@ -750,7 +863,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
StringSeq content = readDirectory(path);
for(StringSeq::const_iterator p = content.begin(); p != content.end() ; ++p)
{
- if(!getFileInfoSeqInt(basePath, normalize(relPath + '/' + *p), compress, cb, infoSeq))
+ if(!getFileInfoSeqInt(path + "/" + *p, compress, cb, infoSeq))
{
return false;
}
@@ -758,12 +871,10 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
}
else if(S_ISREG(buf.st_mode))
{
- FileInfo info;
- info.path = relPath;
info.size = 0;
- ByteSeq bytes(relPath.size() + buf.st_size);
- copy(relPath.begin(), relPath.end(), bytes.begin());
+ ByteSeq bytes(path.size() + buf.st_size);
+ copy(path.begin(), path.end(), bytes.begin());
if(buf.st_size != 0)
{
@@ -777,7 +888,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
throw "cannot open `" + path + "' for reading:\n" + lastError();
}
- if(read(fd, &bytes[relPath.size()], buf.st_size) == -1)
+ if(read(fd, &bytes[path.size()], buf.st_size) == -1)
{
close(fd);
throw "cannot read from `" + path + "':\n" + lastError();
@@ -797,7 +908,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
if(compress >= 2 || stat(pathBZ2.c_str(), &bufBZ2) == -1 || buf.st_mtime >= bufBZ2.st_mtime)
{
- if(cb && !cb->compress(relPath))
+ if(cb && !cb->compress(path))
{
return false;
}
@@ -810,7 +921,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
//
const string pathBZ2Temp = path + ".bz2temp";
- compressBytesToFile(pathBZ2Temp, bytes, relPath.size());
+ compressBytesToFile(pathBZ2Temp, bytes, path.size());
rename(pathBZ2Temp, pathBZ2);
@@ -824,7 +935,7 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
}
}
- if(cb && !cb->checksum(relPath))
+ if(cb && !cb->checksum(path))
{
return false;
}
@@ -849,20 +960,9 @@ getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, G
}
bool
-IcePatch2::getFileInfoSeq(const string& basePath, int compress, GetFileInfoSeqCB* cb,
- FileInfoSeq& infoSeq)
-{
- return getFileInfoSeqSubDir(basePath, ".", compress, cb, infoSeq);
-}
-
-bool
-IcePatch2::getFileInfoSeqSubDir(const string& basePa, const string& relPa, int compress, GetFileInfoSeqCB* cb,
- FileInfoSeq& infoSeq)
+IcePatch2::getFileInfoSeq(const string& path, int compress, GetFileInfoSeqCB* cb, FileInfoSeq& infoSeq)
{
- const string basePath = normalize(basePa);
- const string relPath = normalize(relPa);
-
- if(!getFileInfoSeqInt(basePath, relPath, compress, cb, infoSeq))
+ if(!getFileInfoSeqInt(path, compress, cb, infoSeq))
{
return false;
}
@@ -877,7 +977,7 @@ void
IcePatch2::saveFileInfoSeq(const string& pa, const FileInfoSeq& infoSeq)
{
{
- const string path = normalize(pa + ".sum");
+ const string path = normalize(pa + "/" + checksumFile);
ofstream os(path.c_str());
if(!os)
@@ -892,7 +992,7 @@ IcePatch2::saveFileInfoSeq(const string& pa, const FileInfoSeq& infoSeq)
}
{
- const string pathLog = normalize(pa + ".log");
+ const string pathLog = normalize(pa + "/" + logFile);
try
{
@@ -908,7 +1008,7 @@ void
IcePatch2::loadFileInfoSeq(const string& pa, FileInfoSeq& infoSeq)
{
{
- const string path = normalize(pa + ".sum");
+ const string path = normalize(pa + "/" + checksumFile);
ifstream is(path.c_str());
if(!is)
@@ -932,7 +1032,7 @@ IcePatch2::loadFileInfoSeq(const string& pa, FileInfoSeq& infoSeq)
}
{
- const string pathLog = normalize(pa + ".log");
+ const string pathLog = normalize(pa + "/" + logFile);
ifstream is(pathLog.c_str());
if(is)