summaryrefslogtreecommitdiff
path: root/cpp/src/IcePatch/Util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IcePatch/Util.cpp')
-rw-r--r--cpp/src/IcePatch/Util.cpp329
1 files changed, 329 insertions, 0 deletions
diff --git a/cpp/src/IcePatch/Util.cpp b/cpp/src/IcePatch/Util.cpp
new file mode 100644
index 00000000000..f2191e462fe
--- /dev/null
+++ b/cpp/src/IcePatch/Util.cpp
@@ -0,0 +1,329 @@
+// **********************************************************************
+//
+// Copyright (c) 2002
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#include <IcePatch/Util.h>
+#include <IcePatch/Node.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <openssl/md5.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IcePatch;
+
+static string
+normalizePath(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);
+ }
+
+ return result;
+}
+
+string
+IcePatch::identityToPath(const Identity& identity)
+{
+ assert(identity.category == "IcePatch");
+ return normalizePath(identity.name);
+}
+
+Identity
+IcePatch::pathToIdentity(const string& path)
+{
+ Identity identity;
+ identity.category = "IcePatch";
+ identity.name = normalizePath(path);
+ return identity;
+}
+
+StringSeq
+IcePatch::readDirectory(const string& path)
+{
+ struct dirent **namelist;
+ int n = scandir(path.c_str(), &namelist, 0, alphasort);
+ if (n < 0)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot read directory `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+
+ StringSeq result;
+ result.reserve(n - 2);
+
+ for (int i = 0; i < n; ++i)
+ {
+ string name = namelist[i]->d_name;
+
+ free(namelist[i]);
+
+ if (name != ".." && name != ".")
+ {
+ result.push_back(path + '/' + name);
+ }
+ }
+
+ free(namelist);
+ return result;
+}
+
+ByteSeq
+IcePatch::getMD5(const std::string& path)
+{
+ //
+ // Stat the file to get a MD5 hash value for.
+ //
+ struct stat buf;
+ if (stat(path.c_str(), &buf) == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot stat `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+ else
+ {
+ if (!S_ISREG(buf.st_mode))
+ {
+ NodeAccessException ex;
+ ex.reason = "`" + path + "' is not a regular file";
+ throw ex;
+ }
+ }
+
+ //
+ // Stat the .md5 file. If it doesn't exist, or if it's outdated,
+ // set a flag to create a new MD5 hash value.
+ //
+ struct stat bufmd5;
+ string pathmd5 = path + ".md5";
+ unsigned char md5[16];
+ bool createmd5 = false;
+ if (stat(pathmd5.c_str(), &bufmd5) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ createmd5 = true;
+ }
+ else
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot stat `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+ }
+ else
+ {
+ if (!S_ISREG(bufmd5.st_mode))
+ {
+ NodeAccessException ex;
+ ex.reason = "`" + path + "' is not a regular file";
+ throw ex;
+ }
+
+ if (bufmd5.st_size != 16)
+ {
+ NodeAccessException ex;
+ ex.reason = "`" + path + "' isn't 16 bytes in size";
+ throw ex;
+ }
+
+ if (bufmd5.st_mtime <= buf.st_mtime)
+ {
+ createmd5 = true;
+ }
+ }
+
+ if (createmd5)
+ {
+ //
+ // Open the original file and create a MD5 hash value
+ //
+ {
+ int fd = open(path.c_str(), O_RDONLY);
+
+ if (fd == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot open `" + path + "' for reading:" + strerror(errno);
+ throw ex;
+ }
+
+ unsigned char* fileBuf = new unsigned char[buf.st_size];
+
+ try
+ {
+ int sz = read(fd, fileBuf, buf.st_size);
+
+ if (sz == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot read `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+
+ if (sz < buf.st_size)
+ {
+ NodeAccessException ex;
+ ex.reason = "could not read all bytes from `" + path + "'";
+ throw ex;
+ }
+
+ MD5(fileBuf, sz, md5);
+
+ close(fd);
+ delete [] fileBuf;
+ }
+ catch (...)
+ {
+ close(fd);
+ delete [] fileBuf;
+ throw;
+ }
+ }
+
+ //
+ // Write the MD5 hash value to the corresponding .md5 file.
+ //
+ {
+ int fd = open(pathmd5.c_str(), O_WRONLY | O_CREAT, 00644);
+
+ if (fd == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot open `" + pathmd5 + "' for writing:" + strerror(errno);
+ throw ex;
+ }
+
+ try
+ {
+ int sz = write(fd, md5, 16);
+
+ if (sz == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot read `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+
+ if (sz < 16)
+ {
+ NodeAccessException ex;
+ ex.reason = "could not write 16 bytes to `" + path + "'";
+ throw ex;
+ }
+
+ close(fd);
+ }
+ catch (...)
+ {
+ close(fd);
+ throw;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Read the MD5 hash value from the .md5 file.
+ //
+ int fd = open(pathmd5.c_str(), O_RDONLY);
+
+ if (fd == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot open `" + path + "' for reading:" + strerror(errno);
+ throw ex;
+ }
+
+ try
+ {
+ int sz = read(fd, md5, 16);
+
+ if (sz == -1)
+ {
+ NodeAccessException ex;
+ ex.reason = "cannot read `" + path + "':" + strerror(errno);
+ throw ex;
+ }
+
+ if (sz < 16)
+ {
+ NodeAccessException ex;
+ ex.reason = "could not read 16 bytes from `" + path + "'";
+ throw ex;
+ }
+
+ close(fd);
+ }
+ catch (...)
+ {
+ close(fd);
+ throw;
+ }
+ }
+
+ //
+ // Convert array to byte sequence.
+ //
+ ByteSeq result;
+ result.resize(16);
+ for (int i = 0; i < 16; ++i)
+ {
+ result[i] = md5[i];
+ }
+ return result;
+}
+
+std::string
+IcePatch::MD5ToString(const Ice::ByteSeq& md5)
+{
+ if (md5.size() != 16)
+ {
+ return "illegal MD5 hash code";
+ }
+
+ ostringstream out;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int b = static_cast<int>(md5[i]);
+ if (b < 0)
+ {
+ b += 256;
+ }
+ out << hex << b;
+ }
+
+ return out.str();
+}