diff options
author | Michi Henning <michi@zeroc.com> | 2005-01-11 03:59:42 +0000 |
---|---|---|
committer | Michi Henning <michi@zeroc.com> | 2005-01-11 03:59:42 +0000 |
commit | bfdd46fc78552716f25900de5b75a6aff79c6d7c (patch) | |
tree | b0078934828f0c08be6d5f2bf12757e1010f5ed1 /cpp | |
parent | Commented out the delete[] args calls again -- I couldn't reproduce a (diff) | |
download | ice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.tar.bz2 ice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.tar.xz ice-bfdd46fc78552716f25900de5b75a6aff79c6d7c.zip |
Minor refactoring of IcePatch2.
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/include/IcePatch2/Util.h | 13 | ||||
-rw-r--r-- | cpp/slice/IcePatch2/FileServer.ice | 4 | ||||
-rw-r--r-- | cpp/src/IcePatch2/Calc.cpp | 71 | ||||
-rw-r--r-- | cpp/src/IcePatch2/Client.cpp | 23 | ||||
-rwxr-xr-x | cpp/src/IcePatch2/ClientUtil.cpp | 89 | ||||
-rw-r--r-- | cpp/src/IcePatch2/FileServerI.cpp | 24 | ||||
-rw-r--r-- | cpp/src/IcePatch2/FileServerI.h | 5 | ||||
-rw-r--r-- | cpp/src/IcePatch2/Server.cpp | 85 | ||||
-rw-r--r-- | cpp/src/IcePatch2/Util.cpp | 268 |
9 files changed, 352 insertions, 230 deletions
diff --git a/cpp/include/IcePatch2/Util.h b/cpp/include/IcePatch2/Util.h index 2368fb8a792..8ea209f20cc 100644 --- a/cpp/include/IcePatch2/Util.h +++ b/cpp/include/IcePatch2/Util.h @@ -16,6 +16,9 @@ namespace IcePatch2 { +ICE_PATCH2_API extern const char* checksumFile; +ICE_PATCH2_API extern const char* logFile; + ICE_PATCH2_API std::string lastError(); ICE_PATCH2_API std::string bytesToString(const Ice::ByteSeq&); @@ -105,6 +108,15 @@ struct FileInfoLess: public std::binary_function<const FileInfo&, const FileInfo } }; +struct PathLess: public std::binary_function<const FileInfo&, const FileInfo&, bool> +{ + bool + operator()(const FileInfo& lhs, const FileInfo& rhs) + { + return lhs.path < rhs.path; + } +}; + class ICE_PATCH2_API GetFileInfoSeqCB { public: @@ -117,7 +129,6 @@ public: }; ICE_PATCH2_API bool getFileInfoSeq(const std::string&, int, GetFileInfoSeqCB*, FileInfoSeq&); -ICE_PATCH2_API bool getFileInfoSeqSubDir(const std::string&, const std::string&, int, GetFileInfoSeqCB*, FileInfoSeq&); ICE_PATCH2_API void saveFileInfoSeq(const std::string&, const FileInfoSeq&); ICE_PATCH2_API void loadFileInfoSeq(const std::string&, FileInfoSeq&); diff --git a/cpp/slice/IcePatch2/FileServer.ice b/cpp/slice/IcePatch2/FileServer.ice index c3282bfac43..564fcfa829f 100644 --- a/cpp/slice/IcePatch2/FileServer.ice +++ b/cpp/slice/IcePatch2/FileServer.ice @@ -28,10 +28,10 @@ exception FileAccessException interface FileServer { - ["ami"] nonmutating FileInfoSeq getFileInfo1Seq(int node0) + ["ami"] nonmutating FileInfoSeq getFileInfoSeq(int node) throws NodeOutOfRangeException; - nonmutating ByteSeqSeq getChecksum0Seq(); + nonmutating ByteSeqSeq getChecksumSeq(); nonmutating Ice::ByteSeq getChecksum(); 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) |