summaryrefslogtreecommitdiff
path: root/cpp/src/IcePatch/Calc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IcePatch/Calc.cpp')
-rw-r--r--cpp/src/IcePatch/Calc.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/cpp/src/IcePatch/Calc.cpp b/cpp/src/IcePatch/Calc.cpp
new file mode 100644
index 00000000000..8eb8a98c3a6
--- /dev/null
+++ b/cpp/src/IcePatch/Calc.cpp
@@ -0,0 +1,435 @@
+// **********************************************************************
+//
+// Copyright (c) 2004
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Ice/Ice.h>
+#include <IcePatch/Util.h>
+#include <set>
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch;
+
+class CalcApp : public Application
+{
+public:
+
+ void usage();
+ virtual int run(int, char*[]);
+
+private:
+
+ void update(const string&);
+ Long compare(const string&, const string&);
+
+ bool _totals;
+};
+
+void
+CalcApp::usage()
+{
+ cerr << "Usage: " << appName() << " [options] DIR [OLD_DIR OLD_DIR ...]\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-t Show totals.\n"
+ ;
+}
+
+int
+CalcApp::run(int argc, char* argv[])
+{
+ string dataDir;
+ vector<string> oldDataDirs;
+ _totals = false;
+
+ int i;
+ for(i = 1; i < argc; ++i)
+ {
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
+ {
+ usage();
+ return EXIT_SUCCESS;
+ }
+ else if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0)
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+ else if(strcmp(argv[i], "-t") == 0)
+ {
+ _totals = true;
+ }
+ else if(argv[i][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[i] << "'" << endl;
+ usage();
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(dataDir.empty())
+ {
+ dataDir = argv[i];
+ }
+ else
+ {
+ oldDataDirs.push_back(argv[i]);
+ }
+ }
+ }
+
+ if(dataDir.empty())
+ {
+ cerr << argv[0] << ": no data directory specified" << endl;
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ //
+ // Update the data directory (create .bz2 and .md5 files).
+ //
+ cout << "Updating data directory...";
+ if(_totals)
+ {
+ cout << endl;
+ }
+ else
+ {
+ cout << flush;
+ }
+
+ try
+ {
+ update(dataDir);
+ }
+ catch(const FileAccessException& ex)
+ {
+ cerr << endl << "exception during update:\n" << ex << ":\n" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const Exception& ex)
+ {
+ cerr << endl << "exception during update:\n" << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!_totals)
+ {
+ cout << " done." << endl;
+ }
+
+ if(!oldDataDirs.empty())
+ {
+ for(vector<string>::iterator p = oldDataDirs.begin(); p != oldDataDirs.end(); ++p)
+ {
+ cout << "Comparing with " << *p << "...";
+ if(_totals)
+ {
+ cout << endl;
+ }
+ else
+ {
+ cout << flush;
+ }
+
+ try
+ {
+ compare(*p, dataDir);
+ }
+ catch(const FileAccessException& ex)
+ {
+ cerr << endl << "exception during comparison:\n" << ex << ":\n" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const Exception& ex)
+ {
+ cerr << endl << "exception during comparison:\n" << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!_totals)
+ {
+ cout << " done." << endl;
+ }
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+void
+CalcApp::update(const string& dir)
+{
+ StringSeq contents = readDirectory(dir);
+ StringSeq filteredContents;
+ StringSeq::const_iterator p;
+
+ for(p = contents.begin(); p != contents.end(); ++p)
+ {
+ FileInfo info = getFileInfo(*p, true);
+ if(info.type == FileTypeDirectory)
+ {
+ //
+ // Depth-first traversal.
+ //
+ update(*p);
+ filteredContents.push_back(*p);
+ }
+ else
+ {
+ if(ignoreSuffix(*p))
+ {
+ //
+ // Check for orphans (i.e., bz2 or md5 files for which the original file no longer exists).
+ //
+ string orphan = removeSuffix(*p);
+ FileInfo infoOrphan = getFileInfo(orphan, false);
+ if(infoOrphan.type == FileTypeNotExist)
+ {
+ removeRecursive(*p, 0);
+ }
+ }
+ else
+ {
+ //
+ // Create .bz2 file if necessary.
+ //
+ FileInfo infoBZ2 = getFileInfo(*p + ".bz2", false);
+ if(infoBZ2.type != FileTypeRegular || infoBZ2.time <= info.time)
+ {
+ createBZ2(*p, 0);
+ }
+
+ //
+ // Create .md5 file if necessary.
+ //
+ FileInfo infoMD5 = getFileInfo(*p + ".md5", false);
+ if(infoMD5.type != FileTypeRegular || infoMD5.time <= info.time)
+ {
+ createMD5(*p, 0);
+ }
+
+ filteredContents.push_back(*p);
+ }
+ }
+ }
+
+ //
+ // Create .md5 for directory if necessary.
+ //
+ FileInfo info = getFileInfo(dir, true);
+ FileInfo infoMD5 = getFileInfo(dir + ".md5", false);
+ if(infoMD5.type != FileTypeRegular || infoMD5.time <= info.time)
+ {
+ createMD5(dir, 0);
+ }
+
+ //
+ // Compute totals if necessary.
+ //
+ FileInfo infoTot = getFileInfo(dir + ".tot", false);
+ if(infoTot.type != FileTypeRegular || infoTot.time <= info.time)
+ {
+ Long total = 0;
+ ByteSeq md5; // Empty
+ for(p = filteredContents.begin(); p != filteredContents.end(); ++p)
+ {
+ FileInfo info = getFileInfo(*p, true);
+ if(info.type == FileTypeDirectory)
+ {
+ TotalMap m = getTotalMap(communicator(), *p);
+ TotalMap::iterator q = m.find(md5);
+ assert(q != m.end());
+ total += q->second;
+ }
+ else
+ {
+ FileInfo infoBZ2 = getFileInfo(*p + ".bz2", true);
+ assert(infoBZ2.type == FileTypeRegular);
+ total += infoBZ2.size;
+ }
+ }
+
+ TotalMap totals = getTotalMap(communicator(), dir);
+ TotalMap::iterator q = totals.find(md5);
+ if(q != totals.end())
+ {
+ q->second = total;
+ }
+ else
+ {
+ totals.insert(TotalMap::value_type(md5, total));
+ }
+ if(_totals)
+ {
+ cout << " " << dir << " (" << total << " bytes)" << endl;
+ }
+ putTotalMap(communicator(), dir, totals);
+ }
+ else if(_totals)
+ {
+ TotalMap totals = getTotalMap(communicator(), dir);
+ ByteSeq md5; // Empty
+ TotalMap::iterator q = totals.find(md5);
+ assert(q != totals.end());
+ cout << " " << dir << " (" << q->second << " bytes)" << endl;
+ }
+}
+
+#ifdef _WIN32
+
+typedef set<string, CICompare> EntrySet;
+
+#else
+
+typedef set<string> EntrySet;
+
+#endif
+
+Long
+CalcApp::compare(const string& oldDir, const string& newDir)
+{
+ Long total = 0;
+
+ ByteSeq oldMD5 = getMD5(oldDir);
+ ByteSeq newMD5 = getMD5(newDir);
+ if(oldMD5 != newMD5)
+ {
+ StringSeq oldContents = readDirectory(oldDir, ".");
+ StringSeq newContents = readDirectory(newDir, ".");
+ StringSeq::const_iterator p;
+
+ EntrySet newEntries;
+ copy(newContents.begin(), newContents.end(), inserter(newEntries, newEntries.begin()));
+
+ for(p = oldContents.begin(); p != oldContents.end(); ++p)
+ {
+ if(ignoreSuffix(*p))
+ {
+ continue;
+ }
+
+ string oldEntry = oldDir + "/" + *p;
+ string newEntry = newDir + "/" + *p;
+ FileInfo oldInfo = getFileInfo(oldEntry, true);
+ FileInfo newInfo = getFileInfo(newEntry, false);
+
+ if(newInfo.type == FileTypeNotExist)
+ {
+ continue;
+ }
+
+ if(oldInfo.type == FileTypeDirectory)
+ {
+ if(newInfo.type == FileTypeDirectory)
+ {
+ total += compare(oldEntry, newEntry);
+ }
+ else
+ {
+ FileInfo infoBZ2 = getFileInfo(newEntry + ".bz2", true);
+ total += infoBZ2.size;
+ }
+ }
+ else
+ {
+ if(newInfo.type == FileTypeDirectory)
+ {
+ TotalMap totals = getTotalMap(communicator(), newEntry);
+ ByteSeq empty;
+ TotalMap::const_iterator q = totals.find(empty);
+ if(q != totals.end())
+ {
+ total += q->second;
+ }
+ }
+ else
+ {
+ ByteSeq oldEntryMD5 = getMD5(oldEntry);
+ ByteSeq newEntryMD5 = getMD5(newEntry);
+ if(oldEntryMD5 != newEntryMD5)
+ {
+ FileInfo newEntryBZ2 = getFileInfo(newEntry + ".bz2", true);
+ total += newEntryBZ2.size;
+ }
+ }
+ }
+
+ newEntries.erase(*p);
+ }
+
+ for(EntrySet::iterator q = newEntries.begin(); q != newEntries.end(); ++q)
+ {
+ if(ignoreSuffix(*q))
+ {
+ continue;
+ }
+
+ string entry = newDir + "/" + *q;
+ FileInfo info = getFileInfo(entry, true);
+ if(info.type == FileTypeDirectory)
+ {
+ TotalMap totals = getTotalMap(communicator(), entry);
+ ByteSeq empty;
+ TotalMap::const_iterator r = totals.find(empty);
+ if(r != totals.end())
+ {
+ total += r->second;
+ }
+ }
+ else
+ {
+ assert(info.type == FileTypeRegular);
+ FileInfo infoBZ2 = getFileInfo(entry + ".bz2", true);
+ total += infoBZ2.size;
+ }
+ }
+ }
+
+ //
+ // An MD5 full of zeros indicates an old directory that is empty.
+ // We ignore this case because the difference is simply the size of
+ // the current directory (i.e., an empty MD5).
+ //
+ ByteSeq zeroMD5(16, 0);
+ if(oldMD5 != zeroMD5)
+ {
+ TotalMap totals = getTotalMap(communicator(), newDir);
+ TotalMap::iterator q = totals.find(oldMD5);
+ if(q != totals.end())
+ {
+ q->second = total;
+ }
+ else
+ {
+ totals.insert(TotalMap::value_type(oldMD5, total));
+ }
+ putTotalMap(communicator(), newDir, totals);
+ }
+
+ if(_totals)
+ {
+ cout << " " << newDir << " (" << total << " bytes)" << endl;
+ }
+
+ return total;
+}
+
+int
+main(int argc, char* argv[])
+{
+ CalcApp app;
+ return app.main(argc, argv);
+}