summaryrefslogtreecommitdiff
path: root/cpp/src/IcePatch2
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IcePatch2')
-rw-r--r--cpp/src/IcePatch2/.depend9
-rw-r--r--cpp/src/IcePatch2/Calc.cpp124
-rw-r--r--cpp/src/IcePatch2/Client.cpp403
-rw-r--r--cpp/src/IcePatch2/FileServerI.cpp150
-rw-r--r--cpp/src/IcePatch2/FileServerI.h42
-rw-r--r--cpp/src/IcePatch2/Makefile81
-rw-r--r--cpp/src/IcePatch2/Server.cpp227
-rw-r--r--cpp/src/IcePatch2/Util.cpp806
8 files changed, 1842 insertions, 0 deletions
diff --git a/cpp/src/IcePatch2/.depend b/cpp/src/IcePatch2/.depend
new file mode 100644
index 00000000000..8e218aab1a4
--- /dev/null
+++ b/cpp/src/IcePatch2/.depend
@@ -0,0 +1,9 @@
+Util.o: Util.cpp ../../include/IceUtil/IceUtil.h ../../include/IceUtil/Functional.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/IceUtil/Unicode.h ../../include/IceUtil/UUID.h ../../include/IceUtil/AbstractMutex.h ../../include/IceUtil/RecMutex.h ../../include/IceUtil/RWRecMutex.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/IceUtil/Thread.h ../../include/IceUtil/StaticMutex.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/CountDownLatch.h ../../include/IceUtil/Base64.h ../../include/IceUtil/StringUtil.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../../include/IceUtil/GC.h ../../include/IcePatch2/Util.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/FacetMap.h ../../include/Ice/ServantLocator.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Incoming.h ../../include/Ice/ServantManagerF.h ../../include/Ice/BasicStream.h ../../include/Ice/Buffer.h ../../include/Ice/Process.h ../../include/Ice/Outgoing.h ../../include/Ice/Direct.h ../../include/Ice/Application.h ../../include/Ice/Connection.h ../../include/Ice/Functional.h ../../include/Ice/Stream.h ../../include/IcePatch2/FileInfo.h
+FileInfo.o: FileInfo.cpp ../../include/IcePatch2/FileInfo.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/BasicStream.h ../../include/Ice/InstanceF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h
+FileServer.o: FileServer.cpp ../../include/IcePatch2/FileServer.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/InstanceF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/UserExceptionFactory.h ../../include/Ice/FactoryTable.h ../../include/Ice/FactoryTableDef.h ../../include/IceUtil/StaticMutex.h ../../include/Ice/UserExceptionFactoryF.h ../../include/IcePatch2/FileInfo.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/LocalException.h ../../include/Ice/ObjectFactory.h
+Server.o: Server.cpp ../../include/Ice/Service.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/FacetMap.h ../../include/Ice/ServantLocator.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Incoming.h ../../include/Ice/ServantManagerF.h ../../include/Ice/BasicStream.h ../../include/Ice/Buffer.h ../../include/Ice/Process.h ../../include/Ice/Outgoing.h ../../include/Ice/Direct.h ../../include/Ice/Application.h ../../include/Ice/Connection.h ../../include/Ice/Functional.h ../../include/IceUtil/Functional.h ../../include/Ice/Stream.h ../IcePatch2/FileServerI.h ../../include/IcePatch2/Util.h ../../include/IcePatch2/FileInfo.h ../../include/IcePatch2/FileServer.h ../../include/Ice/UserExceptionFactory.h ../../include/Ice/FactoryTable.h ../../include/Ice/FactoryTableDef.h ../../include/IceUtil/StaticMutex.h ../../include/Ice/UserExceptionFactoryF.h
+FileServerI.o: FileServerI.cpp ../IcePatch2/FileServerI.h ../../include/IcePatch2/Util.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/FacetMap.h ../../include/Ice/ServantLocator.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Incoming.h ../../include/Ice/ServantManagerF.h ../../include/Ice/BasicStream.h ../../include/Ice/Buffer.h ../../include/Ice/Process.h ../../include/Ice/Outgoing.h ../../include/Ice/Direct.h ../../include/Ice/Application.h ../../include/Ice/Connection.h ../../include/Ice/Functional.h ../../include/IceUtil/Functional.h ../../include/Ice/Stream.h ../../include/IcePatch2/FileInfo.h ../../include/IcePatch2/FileServer.h ../../include/Ice/UserExceptionFactory.h ../../include/Ice/FactoryTable.h ../../include/Ice/FactoryTableDef.h ../../include/IceUtil/StaticMutex.h ../../include/Ice/UserExceptionFactoryF.h
+Client.o: Client.cpp ../../include/Ice/Application.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/FacetMap.h ../../include/Ice/ServantLocator.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Incoming.h ../../include/Ice/ServantManagerF.h ../../include/Ice/BasicStream.h ../../include/Ice/Buffer.h ../../include/Ice/Process.h ../../include/Ice/Outgoing.h ../../include/Ice/Direct.h ../../include/Ice/Connection.h ../../include/Ice/Functional.h ../../include/IceUtil/Functional.h ../../include/Ice/Stream.h ../IcePatch2/FileServerI.h ../../include/IcePatch2/Util.h ../../include/IcePatch2/FileInfo.h ../../include/IcePatch2/FileServer.h ../../include/Ice/UserExceptionFactory.h ../../include/Ice/FactoryTable.h ../../include/Ice/FactoryTableDef.h ../../include/IceUtil/StaticMutex.h ../../include/Ice/UserExceptionFactoryF.h
+Calc.o: Calc.cpp ../../include/IcePatch2/Util.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionIF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/ConnectionF.h ../../include/Ice/Identity.h ../../include/Ice/StreamF.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/FacetMap.h ../../include/Ice/ServantLocator.h ../../include/Ice/Object.h ../../include/IceUtil/GCShared.h ../../include/IceUtil/GCRecMutex.h ../../include/IceUtil/RecMutex.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Incoming.h ../../include/Ice/ServantManagerF.h ../../include/Ice/BasicStream.h ../../include/Ice/Buffer.h ../../include/Ice/Process.h ../../include/Ice/Outgoing.h ../../include/Ice/Direct.h ../../include/Ice/Application.h ../../include/Ice/Connection.h ../../include/Ice/Functional.h ../../include/IceUtil/Functional.h ../../include/Ice/Stream.h ../../include/IcePatch2/FileInfo.h
+FileInfo.cpp: ../../slice/IcePatch2/FileInfo.ice ../../slice/Ice/BuiltinSequences.ice
+FileServer.cpp: ../../slice/IcePatch2/FileServer.ice ../../slice/IcePatch2/FileInfo.ice ../../slice/Ice/BuiltinSequences.ice
diff --git a/cpp/src/IcePatch2/Calc.cpp b/cpp/src/IcePatch2/Calc.cpp
new file mode 100644
index 00000000000..4a98f1b6c09
--- /dev/null
+++ b/cpp/src/IcePatch2/Calc.cpp
@@ -0,0 +1,124 @@
+// **********************************************************************
+//
+// Copyright (c) 2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IcePatch2/Util.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch2;
+
+void
+usage(const char* appName)
+{
+ cerr << "Usage: " << appName << " [options] DIR\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-z, --bzip2 Compress files.\n"
+ "-V, --verbose Verbose mode.\n"
+ ;
+}
+
+int
+main(int argc, char* argv[])
+{
+ string dataDir;
+ bool compress = false;
+ bool verbose = false;
+
+ int i;
+ for(i = 1; i < argc; ++i)
+ {
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
+ {
+ usage(argv[0]);
+ 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], "-z") == 0 || strcmp(argv[i], "--bzip2") == 0)
+ {
+ compress = true;
+ }
+ else if(strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--verbose") == 0)
+ {
+ verbose = true;
+ }
+ else if(argv[i][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[i] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(dataDir.empty())
+ {
+ dataDir = argv[i];
+ }
+ else
+ {
+ cerr << argv[0] << ": too many arguments" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ if(dataDir.empty())
+ {
+ cerr << argv[0] << ": no data directory specified" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+#ifdef _WIN32
+ char cwd[_MAX_PATH];
+ if(_getcwd(cwd, _MAX_PATH) == NULL)
+#else
+ char cwd[PATH_MAX];
+ if(getcwd(cwd, PATH_MAX) == NULL)
+#endif
+ {
+ throw string("cannot get the current directory: ") + strerror(errno);
+ }
+
+ dataDir = normalize(string(cwd) + '/' + dataDir);
+
+ if(chdir(dataDir.c_str()) == -1)
+ {
+ throw "cannot change directory to `" + dataDir + "': " + strerror(errno);
+ }
+
+ FileInfoSeq infoSeq;
+ getFileInfoSeq(".", infoSeq, compress, verbose);
+
+ sort(infoSeq.begin(), infoSeq.end(), FileInfoCompare());
+
+ saveFileInfoSeq(dataDir + ".sum", infoSeq);
+ }
+ catch(const string& ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const char* ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cpp/src/IcePatch2/Client.cpp b/cpp/src/IcePatch2/Client.cpp
new file mode 100644
index 00000000000..2d8f9d9352c
--- /dev/null
+++ b/cpp/src/IcePatch2/Client.cpp
@@ -0,0 +1,403 @@
+// **********************************************************************
+//
+// Copyright (c) 2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/Application.h>
+#include <IcePatch2/FileServerI.h>
+#include <IcePatch2/Util.h>
+#include <fstream>
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch2;
+
+namespace IcePatch2
+{
+
+class Client : public Application
+{
+public:
+
+ void usage();
+ virtual int run(int, char*[]);
+
+private:
+
+ void usage(const std::string&);
+};
+
+};
+
+int
+IcePatch2::Client::run(int argc, char* argv[])
+{
+ bool thorough = false;
+ bool dry = false;
+ string dataDir;
+
+ for(int i = 1; i < argc; ++i)
+ {
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ else if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0)
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_FAILURE;
+ }
+ else if(strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--thorough") == 0)
+ {
+ thorough = true;
+ }
+ else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dry") == 0)
+ {
+ dry = true;
+ }
+ else if(argv[i][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[i] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(dataDir.empty())
+ {
+ dataDir = argv[i];
+ }
+ else
+ {
+ cerr << argv[0] << ": too many arguments" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ PropertiesPtr properties = communicator()->getProperties();
+
+ if(dataDir.empty())
+ {
+ string dataDir = properties->getProperty("IcePatch2.Directory");
+ if(dataDir.empty())
+ {
+ cerr << argv[0] << ": no data directory specified" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ Int chunk = properties->getPropertyAsIntWithDefault("IcePatch2.ChunkSize", 100000);
+ if(chunk < 1)
+ {
+ chunk = 1;
+ }
+
+ try
+ {
+ FileInfoSeq infoSeq;
+
+#ifdef _WIN32
+ char cwd[_MAX_PATH];
+ if(_getcwd(cwd, _MAX_PATH) == NULL)
+#else
+ char cwd[PATH_MAX];
+ if(getcwd(cwd, PATH_MAX) == NULL)
+#endif
+ {
+ throw string("cannot get the current directory: ") + strerror(errno);
+ }
+
+ dataDir = normalize(string(cwd) + '/' + dataDir);
+
+ if(chdir(dataDir.c_str()) == -1)
+ {
+ throw "cannot change directory to `" + dataDir + "': " + strerror(errno);
+ }
+
+ if(thorough)
+ {
+ getFileInfoSeq(".", infoSeq, false, false);
+ }
+ else
+ {
+ loadFileInfoSeq(dataDir + ".sum", infoSeq);
+ }
+
+ sort(infoSeq.begin(), infoSeq.end(), FileInfoCompare());
+
+ const char* endpointsProperty = "IcePatch2.Endpoints";
+ const string endpoints = properties->getProperty(endpointsProperty);
+ if(endpoints.empty())
+ {
+ cerr << argv[0] << ": property `" << endpointsProperty << "' is not set" << endl;
+ return EXIT_FAILURE;
+ }
+
+ const char* idProperty = "IcePatch2.Identity";
+ const Identity id = stringToIdentity(properties->getPropertyWithDefault(idProperty, "IcePatch2/server"));
+
+ ObjectPrx fileServerBase = communicator()->stringToProxy(identityToString(id) + ':' + endpoints);
+ FileServerPrx fileServer = FileServerPrx::checkedCast(fileServerBase);
+ if(!fileServer)
+ {
+ cerr << argv[0] << ": proxy `" << identityToString(id) << ':' << endpoints << "' is not a file server."
+ << endl;
+ return EXIT_FAILURE;
+ }
+
+ FileTree0 tree0;
+ getFileTree0(infoSeq, tree0);
+
+ FileInfoSeq removeFiles;
+ FileInfoSeq updateFiles;
+
+ if(tree0.checksum != fileServer->getChecksum0())
+ {
+ ByteSeqSeq checksum1Seq = fileServer->getChecksum1Seq();
+ if(checksum1Seq.size() != 256)
+ {
+ cerr << argv[0] << ": server returned illegal value" << endl;
+ return EXIT_FAILURE;
+ }
+
+ for(int node0 = 0; node0 < 256; ++node0)
+ {
+ if(tree0.nodes[node0].checksum != checksum1Seq[node0])
+ {
+ ByteSeqSeq checksum2Seq = fileServer->getChecksum2Seq(node0);
+ if(checksum2Seq.size() != 256)
+ {
+ cerr << argv[0] << ": server returned illegal value" << endl;
+ return EXIT_FAILURE;
+ }
+
+ for(int node1 = 0; node1 < 256; ++node1)
+ {
+ if(tree0.nodes[node0].nodes[node1].checksum != checksum2Seq[node1])
+ {
+ FileInfoSeq fileSeq = fileServer->getFileInfoSeq(node0, node1);
+ sort(fileSeq.begin(), fileSeq.end(), FileInfoCompare());
+
+ set_difference(tree0.nodes[node0].nodes[node1].files.begin(),
+ tree0.nodes[node0].nodes[node1].files.end(),
+ fileSeq.begin(),
+ fileSeq.end(),
+ back_inserter(removeFiles),
+ FileInfoCompare());
+
+ set_difference(fileSeq.begin(),
+ fileSeq.end(),
+ tree0.nodes[node0].nodes[node1].files.begin(),
+ tree0.nodes[node0].nodes[node1].files.end(),
+ back_inserter(updateFiles),
+ FileInfoCompare());
+ }
+ }
+ }
+ }
+ }
+
+ sort(removeFiles.begin(), removeFiles.end(), FileInfoCompare());
+ sort(updateFiles.begin(), updateFiles.end(), FileInfoCompare());
+
+ //
+ // We remove the summary file, so that if something goes wrong
+ // during patching, the next run has to be done with the
+ // thorough option. Otherwise there could be inconsistencies
+ // between the summary file and the real content.
+ //
+ if(!dry)
+ {
+ removeRecursive(dataDir + ".sum");
+ }
+
+ FileInfoSeq::const_iterator p;
+
+ p = removeFiles.begin();
+ while(p != removeFiles.end())
+ {
+ cout << "remove: " << p->path << endl;
+
+ if(!dry)
+ {
+ try
+ {
+ removeRecursive(p->path);
+ }
+ catch(...)
+ {
+ }
+ }
+
+ string dir = p->path + '/';
+
+ do
+ {
+ ++p;
+ }
+ while(p->path.compare(0, dir.size(), dir) == 0);
+ }
+
+ Long total = 0;
+ Long updated = 0;
+
+ for(p = updateFiles.begin(); p != updateFiles.end(); ++p)
+ {
+ if(p->size > 0) // Regular, non-empty file?
+ {
+ total += p->size;
+ }
+ }
+
+ for(p = updateFiles.begin(); p != updateFiles.end(); ++p)
+ {
+ cout << "update: " << p->path << ' ' << flush;
+
+ if(p->size < 0) // Directory?
+ {
+ if(!dry)
+ {
+ createDirectoryRecursive(p->path);
+ }
+ }
+ else // Regular file.
+ {
+ if(!dry)
+ {
+ string dir = getDirname(p->path);
+ if(!dir.empty())
+ {
+ createDirectoryRecursive(dir);
+ }
+ }
+
+ Int pos = 0;
+ string progress;
+
+ while(pos < p->size)
+ {
+ ByteSeq bytes;
+
+ try
+ {
+ bytes = fileServer->getFileCompressed(p->path, pos, chunk);
+ }
+ catch(const FileAccessException& ex)
+ {
+ cerr << argv[0] << ": server error for `" << p->path << "':" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(bytes.empty())
+ {
+ cerr << argv[0] << ": size mismatch for `" << p->path << "'" << endl;
+ return EXIT_FAILURE;
+ }
+
+ pos += bytes.size();
+ updated += bytes.size();
+
+ for(unsigned int i = 0; i < progress.size(); ++i)
+ {
+ cout << '\b';
+ }
+ ostringstream s;
+ s << pos << '/' << p->size << " (" << updated << '/' << total << ')';
+ progress = s.str();
+ cout << progress << flush;
+ }
+
+/*
+ if(!dry)
+ {
+ try
+ {
+ removeRecursive(p->path);
+ }
+ catch(...)
+ {
+ }
+
+ ofstream os(p->path.c_str());
+ if(!os)
+ {
+ throw "cannot open `" + p->path + "' for writing: " + strerror(errno);
+ }
+ }
+*/
+ }
+
+ cout << endl;
+ }
+
+ //
+ // After a complete and successful patch, we write a new
+ // summary file.
+ //
+ if(!dry)
+ {
+ FileInfoSeq newInfoSeq1;
+ newInfoSeq1.reserve(infoSeq.size());
+
+ set_difference(infoSeq.begin(),
+ infoSeq.end(),
+ removeFiles.begin(),
+ removeFiles.end(),
+ back_inserter(newInfoSeq1),
+ FileInfoCompare());
+
+ FileInfoSeq newInfoSeq2;
+ newInfoSeq2.reserve(newInfoSeq1.size() + updateFiles.size());
+
+ set_union(newInfoSeq1.begin(),
+ newInfoSeq1.end(),
+ updateFiles.begin(),
+ updateFiles.end(),
+ back_inserter(newInfoSeq2),
+ FileInfoCompare());
+
+ saveFileInfoSeq(dataDir + ".sum", newInfoSeq2);
+ }
+ }
+ catch(const string& ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const char* ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+void
+IcePatch2::Client::usage(const string& appName)
+{
+ string options =
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-t, --thorough Recalculate all checksums.\n"
+ "-d, --dry Don't update, do a dry run only.";
+
+ cerr << "Usage: " << appName << " [options] [DIR]" << endl;
+ cerr << options << endl;
+}
+
+int
+main(int argc, char* argv[])
+{
+ Client app;
+ return app.main(argc, argv);
+}
diff --git a/cpp/src/IcePatch2/FileServerI.cpp b/cpp/src/IcePatch2/FileServerI.cpp
new file mode 100644
index 00000000000..85fdc5bb6ce
--- /dev/null
+++ b/cpp/src/IcePatch2/FileServerI.cpp
@@ -0,0 +1,150 @@
+// **********************************************************************
+//
+// Copyright (c) 2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IcePatch2/FileServerI.h>
+
+#ifdef _WIN32
+# include <io.h>
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch2;
+
+IcePatch2::FileServerI::FileServerI(const FileInfoSeq& infoSeq)
+{
+ FileTree0& tree0 = const_cast<FileTree0&>(_tree0);
+ getFileTree0(infoSeq, tree0);
+
+/*
+ assert(tree0.nodes.size() == 256);
+ for(int i = 0; i < 256; ++i)
+ {
+ FileTree1& tree1 = tree0.nodes[i];
+ assert(tree1.nodes.size() == 256);
+ for(int j = 0; j < 256; ++j)
+ {
+ FileTree2& tree2 = tree1.nodes[j];
+ }
+ }
+
+ cout << "Summary ===> " << bytesToString(tree0.checksum) << endl;
+*/
+}
+
+FileInfoSeq
+IcePatch2::FileServerI::getFileInfoSeq(Int node0, Int node1, const Current&) const
+{
+ if(node0 < 0 || node0 > 255)
+ {
+ throw NodeOutOfRangeException();
+ }
+
+ if(node1 < 0 || node1 > 255)
+ {
+ throw NodeOutOfRangeException();
+ }
+
+ return _tree0.nodes[node0].nodes[node1].files;
+}
+
+ByteSeqSeq
+IcePatch2::FileServerI::getChecksum2Seq(Int node0, const Current&) const
+{
+ if(node0 < 0 || node0 > 255)
+ {
+ throw NodeOutOfRangeException();
+ }
+
+ ByteSeqSeq checksums(256);
+
+ for(int node1 = 0; node1 < 256; ++node1)
+ {
+ checksums[node1] = _tree0.nodes[node0].nodes[node1].checksum;
+ }
+
+ return checksums;
+}
+
+ByteSeqSeq
+IcePatch2::FileServerI::getChecksum1Seq(const Current&) const
+{
+ ByteSeqSeq checksums(256);
+
+ for(int node0 = 0; node0 < 256; ++node0)
+ {
+ checksums[node0] = _tree0.nodes[node0].checksum;
+ }
+
+ return checksums;
+}
+
+ByteSeq
+IcePatch2::FileServerI::getChecksum0(const Current&) const
+{
+ return _tree0.checksum;
+}
+
+ByteSeq
+IcePatch2::FileServerI::getFileCompressed(const string& pa, Int pos, Int num, const Current&) const
+{
+ string path = normalize(pa);
+ path += ".bz2";
+
+ if(num <= 0 || pos < 0)
+ {
+ return ByteSeq();
+ }
+
+ if(num > 256 * 1024)
+ {
+ num = 256 * 1024;
+ }
+
+ int fd = open(path.c_str(), O_RDONLY);
+ if(fd == -1)
+ {
+ FileAccessException ex;
+ ex.reason = "cannot open `" + path + "' for reading: " + strerror(errno);
+ throw ex;
+ }
+
+ if(lseek(fd, static_cast<off_t>(pos), SEEK_SET) != static_cast<off_t>(pos))
+ {
+ close(fd);
+
+ ostringstream posStr;
+ posStr << pos;
+
+ FileAccessException ex;
+ ex.reason = "cannot seek position " + posStr.str() + " in file `" + path + "': " + strerror(errno);
+ throw ex;
+ }
+
+ ByteSeq bytes(num);
+ ssize_t r;
+ if((r = read(fd, &bytes[0], static_cast<size_t>(num))) == -1)
+ {
+ close(fd);
+
+ FileAccessException ex;
+ ex.reason = "cannot read `" + path + "': " + strerror(errno);
+ throw ex;
+ }
+
+ close(fd);
+
+ bytes.resize(r);
+ return bytes;
+}
diff --git a/cpp/src/IcePatch2/FileServerI.h b/cpp/src/IcePatch2/FileServerI.h
new file mode 100644
index 00000000000..29136554afe
--- /dev/null
+++ b/cpp/src/IcePatch2/FileServerI.h
@@ -0,0 +1,42 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifndef ICE_PATCH2_FILE_SERVER_I_H
+#define ICE_PATCH2_FILE_SERVER_I_H
+
+#include <IcePatch2/Util.h>
+#include <IcePatch2/FileServer.h>
+
+namespace IcePatch2
+{
+
+class FileServerI : public FileServer
+{
+public:
+
+ FileServerI(const FileInfoSeq&);
+
+ FileInfoSeq getFileInfoSeq(Ice::Int, Ice::Int, const Ice::Current&) const;
+
+ ByteSeqSeq getChecksum2Seq(Ice::Int, const Ice::Current&) const;
+
+ ByteSeqSeq getChecksum1Seq(const Ice::Current&) const;
+
+ Ice::ByteSeq getChecksum0(const Ice::Current&) const;
+
+ Ice::ByteSeq getFileCompressed(const std::string&, Ice::Int pos, Ice::Int num, const Ice::Current&) const;
+
+private:
+
+ const FileTree0 _tree0;
+};
+
+}
+
+#endif
diff --git a/cpp/src/IcePatch2/Makefile b/cpp/src/IcePatch2/Makefile
new file mode 100644
index 00000000000..3f9ea8cde82
--- /dev/null
+++ b/cpp/src/IcePatch2/Makefile
@@ -0,0 +1,81 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2004 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+LIBFILENAME = $(call mklibfilename,IcePatch2,$(VERSION))
+SONAME = $(call mksoname,IcePatch2,$(SOVERSION))
+LIBNAME = $(call mklibname,IcePatch2)
+
+SERVER = $(top_srcdir)/bin/icepatch2server
+CLIENT = $(top_srcdir)/bin/icepatch2client
+CALC = $(top_srcdir)/bin/icepatch2calc
+
+LIBTARGETS = $(call mklibtargets,$(libdir)/$(LIBFILENAME),$(libdir)/$(SONAME),$(libdir)/$(LIBNAME))
+TARGETS = $(LIBTARGETS) $(SERVER) $(CLIENT) $(CALC)
+
+OBJS = Util.o \
+ FileInfo.o \
+ FileServer.o
+
+SOBJS = Server.o \
+ FileServerI.o
+
+COBJS = Client.o
+
+CALCOBJS = Calc.o
+
+SRCS = $(OBJS:.o=.cpp) \
+ $(SOBJS:.o=.cpp) \
+ $(COBJS:.o=.cpp) \
+ $(CALCOBJS:.o=.cpp)
+
+SLICE_SRCS = $(SDIR)/FileInfo.ice \
+ $(SDIR)/FileServer.ice
+
+HDIR = $(includedir)/IcePatch2
+SDIR = $(slicedir)/IcePatch2
+
+include $(top_srcdir)/config/Make.rules
+
+CPPFLAGS := -I.. $(CPPFLAGS) -DICEPATCH2_API_EXPORTS $(OPENSSL_FLAGS)
+SLICE2CPPFLAGS := --ice --include-dir IcePatch2 --dll-export ICEPATCH2_API $(SLICE2CPPFLAGS)
+LINKWITH := -lIce -lIceUtil
+
+$(libdir)/$(LIBFILENAME): $(OBJS)
+ rm -f $@
+ $(call mkshlib,$@,$(SONAME),$(OBJS),$(LINKWITH))
+
+$(libdir)/$(SONAME): $(libdir)/$(LIBFILENAME)
+ rm -f $@
+ ln -s $(LIBFILENAME) $@
+
+$(libdir)/$(LIBNAME): $(libdir)/$(SONAME)
+ rm -f $@
+ ln -s $(SONAME) $@
+
+$(SERVER): $(SOBJS) $(LIBTARGETS)
+ rm -f $@
+ $(CXX) $(LDFLAGS) -o $@ $(SOBJS) -lIcePatch2 $(LIBS) $(OPENSSL_LIBS)
+
+$(CLIENT): $(COBJS) $(LIBTARGETS)
+ rm -f $@
+ $(CXX) $(LDFLAGS) -o $@ $(COBJS) -lIcePatch2 $(LIBS) $(OPENSSL_LIBS)
+
+$(CALC): $(CALCOBJS) $(LIBTARGETS)
+ rm -f $@
+ $(CXX) $(LDFLAGS) -o $@ $(CALCOBJS) -lIcePatch2 $(LIBS) $(OPENSSL_LIBS)
+
+install:: all
+ $(call installlib,$(install_libdir),$(libdir),$(LIBFILENAME),$(SONAME),$(LIBNAME))
+ $(INSTALL_PROGRAM) $(SERVER) $(install_bindir)
+ $(INSTALL_PROGRAM) $(CLIENT) $(install_bindir)
+ $(INSTALL_PROGRAM) $(CALC) $(install_bindir)
+
+include .depend
diff --git a/cpp/src/IcePatch2/Server.cpp b/cpp/src/IcePatch2/Server.cpp
new file mode 100644
index 00000000000..2ad9f40eafc
--- /dev/null
+++ b/cpp/src/IcePatch2/Server.cpp
@@ -0,0 +1,227 @@
+// **********************************************************************
+//
+// Copyright (c) 2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/Service.h>
+#include <IcePatch2/FileServerI.h>
+#include <IcePatch2/Util.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch2;
+
+namespace IcePatch2
+{
+
+class PatcherService : public Service
+{
+public:
+
+ PatcherService();
+
+protected:
+
+ virtual bool start(int, char*[]);
+ virtual bool stop();
+ virtual CommunicatorPtr initializeCommunicator(int&, char*[]);
+
+private:
+
+ void usage(const std::string&);
+};
+
+};
+
+IcePatch2::PatcherService::PatcherService()
+{
+}
+
+bool
+IcePatch2::PatcherService::start(int argc, char* argv[])
+{
+ string dataDir;
+
+ for(int i = 1; i < argc; ++i)
+ {
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
+ {
+ usage(argv[0]);
+ return false;
+ }
+ else if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0)
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return false;
+ }
+ else if(argv[i][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[i] << "'" << endl;
+ usage(argv[0]);
+ return false;
+ }
+ else
+ {
+ if(dataDir.empty())
+ {
+ dataDir = argv[i];
+ }
+ else
+ {
+ cerr << argv[0] << ": too many arguments" << endl;
+ usage(argv[0]);
+ return false;
+ }
+ }
+ }
+
+ PropertiesPtr properties = communicator()->getProperties();
+
+ if(dataDir.empty())
+ {
+ string dataDir = properties->getProperty("IcePatch2.Directory");
+ if(dataDir.empty())
+ {
+ cerr << argv[0] << ": no data directory specified" << endl;
+ usage(argv[0]);
+ return false;
+ }
+ }
+
+ FileInfoSeq infoSeq;
+
+ try
+ {
+#ifdef _WIN32
+ char cwd[_MAX_PATH];
+ if(_getcwd(cwd, _MAX_PATH) == NULL)
+#else
+ char cwd[PATH_MAX];
+ if(getcwd(cwd, PATH_MAX) == NULL)
+#endif
+ {
+ throw string("cannot get the current directory: ") + strerror(errno);
+ }
+
+ dataDir = normalize(string(cwd) + '/' + dataDir);
+
+ if(chdir(dataDir.c_str()) == -1)
+ {
+ throw "cannot change directory to `" + dataDir + "': " + strerror(errno);
+ }
+
+ loadFileInfoSeq(dataDir + ".sum", infoSeq);
+
+ sort(infoSeq.begin(), infoSeq.end(), FileInfoCompare());
+ }
+ catch(const string& ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return false;
+ }
+ catch(const char* ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return false;
+ }
+
+ const char* endpointsProperty = "IcePatch2.Endpoints";
+ if(properties->getProperty(endpointsProperty).empty())
+ {
+ cerr << argv[0] << ": property `" << endpointsProperty << "' is not set" << endl;
+ return false;
+ }
+ ObjectAdapterPtr adapter = communicator()->createObjectAdapter("IcePatch2");
+
+ const char* adminEndpointsProperty = "IcePatch2.Admin.Endpoints";
+ ObjectAdapterPtr adminAdapter;
+ if(!properties->getProperty(adminEndpointsProperty).empty())
+ {
+ adminAdapter = communicator()->createObjectAdapter("IcePatch2.Admin");
+ }
+
+ const char* idProperty = "IcePatch2.Identity";
+ Identity id = stringToIdentity(properties->getPropertyWithDefault(idProperty, "IcePatch2/server"));
+ adapter->add(new FileServerI(infoSeq), id);
+
+ if(adminAdapter)
+ {
+ const char* adminIdProperty = "IcePatch2.AdminIdentity";
+ Identity adminId = stringToIdentity(properties->getPropertyWithDefault(adminIdProperty, "IcePatch2/admin"));
+// adminAdapter->add(new AdminI(communicator()), adminId);
+ }
+
+ adapter->activate();
+ if(adminAdapter)
+ {
+ adminAdapter->activate();
+ }
+
+ return true;
+}
+
+bool
+IcePatch2::PatcherService::stop()
+{
+ return true;
+}
+
+CommunicatorPtr
+IcePatch2::PatcherService::initializeCommunicator(int& argc, char* argv[])
+{
+ return Service::initializeCommunicator(argc, argv);
+}
+
+void
+IcePatch2::PatcherService::usage(const string& appName)
+{
+ string options =
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.";
+#ifdef _WIN32
+ if(checkSystem())
+ {
+ options.append(
+ "\n"
+ "\n"
+ "--service NAME Run as the Windows service NAME.\n"
+ "\n"
+ "--install NAME [--display DISP] [--executable EXEC] [args]\n"
+ " Install as Windows service NAME. If DISP is\n"
+ " provided, use it as the display name,\n"
+ " otherwise NAME is used. If EXEC is provided,\n"
+ " use it as the service executable, otherwise\n"
+ " this executable is used. Any additional\n"
+ " arguments are passed unchanged to the\n"
+ " service at startup.\n"
+ "--uninstall NAME Uninstall Windows service NAME.\n"
+ "--start NAME [args] Start Windows service NAME. Any additional\n"
+ " arguments are passed unchanged to the\n"
+ " service.\n"
+ "--stop NAME Stop Windows service NAME."
+ );
+ }
+#else
+ options.append(
+ "\n"
+ "\n"
+ "--daemon Run as a daemon.\n"
+ "--noclose Do not close open file descriptors.\n"
+ "--nochdir Do not change the current working directory."
+ );
+#endif
+ cerr << "Usage: " << appName << " [options] [DIR]" << endl;
+ cerr << options << endl;
+}
+
+int
+main(int argc, char* argv[])
+{
+ IcePatch2::PatcherService svc;
+ return svc.main(argc, argv);
+}
diff --git a/cpp/src/IcePatch2/Util.cpp b/cpp/src/IcePatch2/Util.cpp
new file mode 100644
index 00000000000..2e4116f7a10
--- /dev/null
+++ b/cpp/src/IcePatch2/Util.cpp
@@ -0,0 +1,806 @@
+// **********************************************************************
+//
+// Copyright (c) 2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/IceUtil.h>
+#include <IcePatch2/Util.h>
+#include <openssl/sha.h>
+#include <bzlib.h>
+#include <iomanip>
+
+#ifdef _WIN32
+# include <direct.h>
+# include <io.h>
+# define S_ISDIR(mode) ((mode) & _S_IFDIR)
+# define S_ISREG(mode) ((mode) & _S_IFREG)
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
+//
+// Sun-OS doesn't have scandir() or alphasort().
+//
+#ifdef __sun
+
+static int
+scandir(const char* dir, struct dirent*** namelist,
+ int (*select)(const struct dirent*),
+ int (*compar)(const void*, const void*))
+{
+ DIR* d;
+ struct dirent* entry;
+ register int i = 0;
+ size_t entrysize;
+
+ if((d = opendir(dir)) == 0)
+ {
+ return -1;
+ }
+
+ *namelist = 0;
+ while((entry = readdir(d)) != 0)
+ {
+ if(select == 0 || (select != 0 && (*select)(entry)))
+ {
+ *namelist = (struct dirent**)realloc((void*)(*namelist), (size_t)((i + 1) * sizeof(struct dirent*)));
+ if(*namelist == 0)
+ {
+ return -1;
+ }
+
+ entrysize = sizeof(struct dirent) - sizeof(entry->d_name) + strlen(entry->d_name) + 1;
+ (*namelist)[i] = (struct dirent*)malloc(entrysize);
+ if((*namelist)[i] == 0)
+ {
+ return -1;
+ }
+ memcpy((*namelist)[i], entry, entrysize);
+ ++i;
+ }
+ }
+
+ if(closedir(d))
+ {
+ return -1;
+ }
+
+ if(i == 0)
+ {
+ return -1;
+ }
+
+ if(compar != 0)
+ {
+ qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
+ }
+
+ return i;
+}
+
+static int
+alphasort(const void* v1, const void* v2)
+{
+ const struct dirent **a = (const struct dirent **)v1;
+ const struct dirent **b = (const struct dirent **)v2;
+ return(strcmp((*a)->d_name, (*b)->d_name));
+}
+
+#endif
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch2;
+
+string
+IcePatch2::bytesToString(const ByteSeq& bytes)
+{
+ ostringstream s;
+ for(ByteSeq::const_iterator p = bytes.begin(); p != bytes.end(); ++p)
+ {
+ s << setw(2) << setfill('0') << hex << static_cast<int>(*p);
+ }
+ return s.str();
+}
+
+ByteSeq
+IcePatch2::stringToBytes(const string& str)
+{
+ ByteSeq bytes;
+ bytes.reserve((str.size() + 1) / 2);
+
+ for(unsigned int i = 0; i + 1 < str.size(); i += 2)
+ {
+ istringstream is(str.substr(i, 2));
+
+ int byte;
+ is >> hex >> byte;
+
+ bytes.push_back(static_cast<Byte>(byte));
+ }
+
+ return bytes;
+}
+
+string
+IcePatch2::normalize(const string& path)
+{
+ string result = path;
+
+ string::size_type pos;
+
+ for(pos = 0; pos < result.size(); ++pos)
+ {
+ if(result[pos] == '\\')
+ {
+ result[pos] = '/';
+ }
+ }
+
+ pos = 0;
+ while((pos = result.find("//", pos)) != string::npos)
+ {
+ result.erase(pos, 1);
+ }
+
+ pos = 0;
+ while((pos = result.find("/./", pos)) != string::npos)
+ {
+ result.erase(pos, 2);
+ }
+
+ if(result.substr(0, 2) == "./")
+ {
+ result.erase(0, 2);
+ }
+
+ if(result.size() >= 2 && result.substr(result.size() - 2, 2) == "/.")
+ {
+ result.erase(result.size() - 2, 2);
+ }
+
+ if(result.size() >= 1 && result[result.size() - 1] == '/')
+ {
+ result.erase(result.size() - 1);
+ }
+
+ 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);
+ }
+}
+
+string
+IcePatch2::getWithoutSuffix(const string& pa)
+{
+ const string path = normalize(pa);
+
+ string::size_type pos = path.rfind('.');
+ if(pos == string::npos)
+ {
+ return path;
+ }
+ else
+ {
+ return path.substr(0, pos);
+ }
+}
+
+bool
+IcePatch2::ignoreSuffix(const string& path)
+{
+ string suffix = getSuffix(path);
+ return suffix == "bz2";
+}
+
+string
+IcePatch2::getBasename(const string& pa)
+{
+ const string path = normalize(pa);
+
+ string::size_type pos = path.rfind('/');
+ if(pos == string::npos)
+ {
+ return path;
+ }
+ else
+ {
+ return path.substr(pos + 1);
+ }
+}
+
+string
+IcePatch2::getDirname(const string& pa)
+{
+ const string path = normalize(pa);
+
+ string::size_type pos = path.rfind('/');
+ if(pos == string::npos)
+ {
+ return string();
+ }
+ else
+ {
+ return path.substr(0, pos);
+ }
+}
+
+void
+IcePatch2::remove(const string& pa)
+{
+ const string path = normalize(pa);
+
+ if(::remove(path.c_str()) == -1)
+ {
+ throw "cannot remove file `" + path + "': " + strerror(errno);
+ }
+}
+
+void
+IcePatch2::removeRecursive(const string& pa)
+{
+ const string path = normalize(pa);
+
+ struct stat buf;
+ if(stat(path.c_str(), &buf) == -1)
+ {
+ throw "cannot stat `" + path + "': " + strerror(errno);
+ }
+
+ if(S_ISDIR(buf.st_mode))
+ {
+ StringSeq paths = readDirectory(path);
+ for(StringSeq::const_iterator p = paths.begin(); p != paths.end(); ++p)
+ {
+ removeRecursive(*p);
+ }
+
+#ifdef _WIN32
+ if(_rmdir(path.c_str()) == -1)
+#else
+ if(rmdir(path.c_str()) == -1)
+#endif
+ {
+ throw "cannot remove directory `" + path + "': " + strerror(errno);
+ }
+ }
+ else
+ {
+ remove(path);
+ }
+}
+
+StringSeq
+IcePatch2::readDirectory(const string& pa)
+{
+ const string path = normalize(pa);
+
+#ifdef _WIN32
+
+ struct _finddata_t data;
+ long h = _findfirst((path + "/*").c_str(), &data);
+ if(h == -1)
+ {
+ throw "cannot read directory `" + path + "': " + strerror(errno);
+ }
+
+ StringSeq result;
+
+ while(true)
+ {
+ string name = data.name;
+ assert(!name.empty());
+
+ if(name != ".." && name != ".")
+ {
+ result.push_back(name);
+ }
+
+ if(_findnext(h, &data) == -1)
+ {
+ if(errno == ENOENT)
+ {
+ break;
+ }
+
+ string ex = "cannot read directory `" + path + "': " + strerror(errno);
+ _findclose(h);
+ throw ex;
+ }
+ }
+
+ _findclose(h);
+
+ sort(result.begin(), result.end());
+
+ return result;
+
+#else
+
+ struct dirent **namelist;
+ int n = scandir(path.c_str(), &namelist, 0, alphasort);
+ if(n < 0)
+ {
+ throw "cannot read directory `" + path + "': " + strerror(errno);
+ }
+
+ StringSeq result;
+ result.reserve(n - 2);
+
+ for(int i = 0; i < n; ++i)
+ {
+ string name = namelist[i]->d_name;
+ assert(!name.empty());
+
+ free(namelist[i]);
+
+ if(name != ".." && name != ".")
+ {
+ result.push_back(name);
+ }
+ }
+
+ free(namelist);
+ return result;
+
+#endif
+}
+
+void
+IcePatch2::createDirectoryRecursive(const string& pa)
+{
+ const string path = normalize(pa);
+
+ string dir = getDirname(path);
+ if(!dir.empty())
+ {
+ createDirectoryRecursive(dir);
+ }
+
+ if(mkdir(path.c_str(), 0777) == -1)
+ {
+ if(errno != EEXIST)
+ {
+ throw "cannot create directory `" + path + "': " + strerror(errno);
+ }
+ }
+}
+
+void
+IcePatch2::compressToFile(const string& path, const ByteSeq& bytes, Int pos)
+{
+ FILE* stdioFileBZ2 = fopen(path.c_str(), "wb");
+ if(!stdioFileBZ2)
+ {
+ throw "cannot open `" + path + "' for writing: " + strerror(errno);
+ }
+
+ int bzError;
+ BZFILE* bzFile = BZ2_bzWriteOpen(&bzError, stdioFileBZ2, 5, 0, 0);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWriteOpen failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ BZ2_bzWrite(&bzError, bzFile, const_cast<Byte*>(&bytes[pos]), bytes.size() - pos);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWrite failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWriteClose failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ fclose(stdioFileBZ2);
+}
+
+void
+IcePatch2::uncompressToFile(const string& path, const ByteSeq& bytes, Int pos)
+{
+ FILE* stdioFileBZ2 = fopen(path.c_str(), "wb");
+ if(!stdioFileBZ2)
+ {
+ throw "cannot open `" + path + "' for writing: " + strerror(errno);
+ }
+
+ int bzError;
+ BZFILE* bzFile = BZ2_bzWriteOpen(&bzError, stdioFileBZ2, 5, 0, 0);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWriteOpen failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ BZ2_bzWrite(&bzError, bzFile, const_cast<Byte*>(&bytes[pos]), bytes.size() - pos);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWrite failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
+ if(bzError != BZ_OK)
+ {
+ string ex = "BZ2_bzWriteClose failed";
+ if(bzError == BZ_IO_ERROR)
+ {
+ ex += string(": ") + strerror(errno);
+ }
+ fclose(stdioFileBZ2);
+ throw ex;
+ }
+
+ fclose(stdioFileBZ2);
+}
+
+void
+IcePatch2::getFileInfoSeq(const string& pa, FileInfoSeq& infoSeq, bool compress, bool verbose)
+{
+ const string path = normalize(pa);
+
+ if(ignoreSuffix(path))
+ {
+ string pathWithoutSuffix = getWithoutSuffix(path);
+
+ if(ignoreSuffix(pathWithoutSuffix))
+ {
+ if(verbose)
+ {
+ cout << path << ": removing " << getSuffix(path) << " file for "
+ << getSuffix(pathWithoutSuffix) << " file" << endl;
+ }
+
+ remove(path);
+ }
+ else
+ {
+ struct stat buf;
+ if(stat(getWithoutSuffix(path).c_str(), &buf) == -1)
+ {
+ if(errno == ENOENT)
+ {
+ if(verbose)
+ {
+ cout << path << ": removing orphaned " << getSuffix(path) << " file" << endl;
+ }
+ remove(path);
+ }
+ else
+ {
+ throw "cannot stat `" + path + "': " + strerror(errno);
+ }
+ }
+ else if(buf.st_size == 0)
+ {
+ if(verbose)
+ {
+ cout << path << ": removing " << getSuffix(path) << " file for empty file" << endl;
+ }
+ remove(path);
+ }
+ }
+
+ return;
+ }
+
+ struct stat buf;
+ if(stat(path.c_str(), &buf) == -1)
+ {
+ throw "cannot stat `" + path + "': " + strerror(errno);
+ }
+
+ if(S_ISDIR(buf.st_mode))
+ {
+ FileInfo info;
+ info.path = path;
+ info.size = -1;
+
+ ByteSeq bytes(path.size());
+ copy(path.begin(), path.end(), bytes.begin());
+
+ ByteSeq bytesSHA(20);
+ SHA1(reinterpret_cast<unsigned char*>(&bytes[0]), bytes.size(),
+ reinterpret_cast<unsigned char*>(&bytesSHA[0]));
+ info.checksum.swap(bytesSHA);
+
+ infoSeq.push_back(info);
+
+ StringSeq content = readDirectory(path);
+ for(StringSeq::const_iterator p = content.begin(); p != content.end() ; ++p)
+ {
+ getFileInfoSeq(path + '/' + *p, infoSeq, compress, verbose);
+ }
+ }
+ else if(S_ISREG(buf.st_mode))
+ {
+ FileInfo info;
+ info.path = path;
+ info.size = 0;
+
+ ByteSeq bytes(path.size() + buf.st_size);
+ copy(path.begin(), path.end(), bytes.begin());
+
+ if(buf.st_size != 0)
+ {
+ if(verbose)
+ {
+ if(compress)
+ {
+ cout << path << ": calculating checksum and compressing file" << endl;
+ }
+ else
+ {
+ cout << path << ": calculating checksum" << endl;
+ }
+ }
+
+ int fd = open(path.c_str(), O_RDONLY);
+ if(fd == -1)
+ {
+ throw "cannot open `" + path + "' for reading: " + strerror(errno);
+ }
+
+ if(read(fd, &bytes[path.size()], buf.st_size) == -1)
+ {
+ close(fd);
+ throw "cannot read `" + path + "': " + strerror(errno);
+ }
+
+ close(fd);
+
+ if(compress)
+ {
+ string pathBZ2 = path + ".bz2";
+ compressToFile(pathBZ2, bytes, path.size());
+
+ struct stat bufBZ2;
+ if(stat(pathBZ2.c_str(), &bufBZ2) == -1)
+ {
+ throw "cannot stat `" + pathBZ2 + "': " + strerror(errno);
+ }
+
+ info.size = bufBZ2.st_size;
+ }
+ }
+ else
+ {
+ if(verbose)
+ {
+ cout << path << ": calculating checksum for empty file" << endl;
+ }
+ }
+
+ ByteSeq bytesSHA(20);
+ SHA1(reinterpret_cast<unsigned char*>(&bytes[0]), bytes.size(),
+ reinterpret_cast<unsigned char*>(&bytesSHA[0]));
+ info.checksum.swap(bytesSHA);
+
+ infoSeq.push_back(info);
+ }
+ else
+ {
+ if(verbose)
+ {
+ cout << path << ": ignoring unknown file type" << endl;
+ }
+ }
+}
+
+void
+IcePatch2::saveFileInfoSeq(const string& path, const FileInfoSeq& infoSeq)
+{
+ ofstream os(path.c_str());
+ if(!os)
+ {
+ throw "cannot open `" + path + "' for writing: " + strerror(errno);
+ }
+
+ for(FileInfoSeq::const_iterator p = infoSeq.begin(); p != infoSeq.end(); ++p)
+ {
+ os << *p << '\n';
+ }
+}
+
+void
+IcePatch2::loadFileInfoSeq(const string& path, FileInfoSeq& infoSeq)
+{
+ ifstream is(path.c_str());
+ if(!is)
+ {
+ throw "cannot open `" + path + "' for reading: " + strerror(errno);
+ }
+
+ while(is.good())
+ {
+ FileInfo info;
+ is >> info;
+
+ if(is.good())
+ {
+ infoSeq.push_back(info);
+ }
+ }
+}
+
+void
+IcePatch2::getFileTree0(const FileInfoSeq& infoSeq, FileTree0& tree0)
+{
+ tree0.nodes.resize(256);
+
+ ByteSeq allChecksums;
+ allChecksums.resize(256 * 20);
+ ByteSeq::iterator q = allChecksums.begin();
+
+ for(int i = 0; i < 256; ++i)
+ {
+ FileInfoSeq infoSeq1;
+
+ for(FileInfoSeq::const_iterator p = infoSeq.begin(); p != infoSeq.end(); ++p)
+ {
+ if(i == static_cast<int>(p->checksum[20 - 2]))
+ {
+ infoSeq1.push_back(*p);
+ }
+ }
+
+ getFileTree1(infoSeq1, tree0.nodes[i]);
+
+ assert(tree0.nodes[i].checksum.size() == 20);
+ copy(tree0.nodes[i].checksum.begin(), tree0.nodes[i].checksum.end(), q);
+
+ q += 20;
+ }
+
+ tree0.checksum.resize(20);
+ SHA1(reinterpret_cast<unsigned char*>(&allChecksums[0]), allChecksums.size(),
+ reinterpret_cast<unsigned char*>(&tree0.checksum[0]));
+}
+
+void
+IcePatch2::getFileTree1(const FileInfoSeq& infoSeq, FileTree1& tree1)
+{
+ tree1.nodes.resize(256);
+
+ ByteSeq allChecksums;
+ allChecksums.resize(256 * 20);
+ ByteSeq::iterator q = allChecksums.begin();
+
+ for(int i = 0; i < 256; ++i)
+ {
+ FileInfoSeq infoSeq2;
+
+ for(FileInfoSeq::const_iterator p = infoSeq.begin(); p != infoSeq.end(); ++p)
+ {
+ if(i == static_cast<int>(p->checksum[20 - 1]))
+ {
+ infoSeq2.push_back(*p);
+ }
+ }
+
+ getFileTree2(infoSeq2, tree1.nodes[i]);
+
+ assert(tree1.nodes[i].checksum.size() == 20);
+ copy(tree1.nodes[i].checksum.begin(), tree1.nodes[i].checksum.end(), q);
+
+ q += 20;
+ }
+
+ tree1.checksum.resize(20);
+ SHA1(reinterpret_cast<unsigned char*>(&allChecksums[0]), allChecksums.size(),
+ reinterpret_cast<unsigned char*>(&tree1.checksum[0]));
+}
+
+void
+IcePatch2::getFileTree2(const FileInfoSeq& infoSeq, FileTree2& tree2)
+{
+ if(infoSeq.empty())
+ {
+ tree2.files.clear();
+ tree2.checksum.resize(20, 0);
+ }
+ else
+ {
+ tree2.files.reserve(infoSeq.size());
+
+ FileInfoSeq::const_iterator p = infoSeq.begin();
+
+ ByteSeq allChecksums;
+ allChecksums.resize(infoSeq.size() * 20);
+ ByteSeq::iterator q = allChecksums.begin();
+
+ while(p < infoSeq.end())
+ {
+ tree2.files.push_back(*p);
+
+ assert(p->checksum.size() == 20);
+ copy(p->checksum.begin(), p->checksum.end(), q);
+
+ ++p;
+ q += 20;
+ }
+
+ sort(tree2.files.begin(), tree2.files.end(), FileInfoCompare());
+
+ tree2.checksum.resize(20);
+ SHA1(reinterpret_cast<unsigned char*>(&allChecksums[0]), allChecksums.size(),
+ reinterpret_cast<unsigned char*>(&tree2.checksum[0]));
+ }
+}
+
+ostream&
+IcePatch2::operator<<(ostream& os, const FileInfo& info)
+{
+ os << IceUtil::escapeString(info.path, "") << '\t' << bytesToString(info.checksum) << '\t' << info.size;
+ return os;
+}
+
+istream&
+IcePatch2::operator>>(istream& is, FileInfo& info)
+{
+ string s;
+
+ getline(is, s, '\t');
+ info.path = s;
+
+ getline(is, s, '\t');
+ info.checksum = stringToBytes(s);
+
+ getline(is, s, '\n');
+ info.size = atoi(s.c_str());
+
+ return is;
+}