Basic implementation of ObjectDb and ObjectManager. Local files can be
put as a set of fully formatted ContentObjects to the ObjectDb, and
extracted from this Db.
diff --git a/src/ccnx-pco.cpp b/src/ccnx-pco.cpp
index af10c7a..8c2fd3f 100644
--- a/src/ccnx-pco.cpp
+++ b/src/ccnx-pco.cpp
@@ -54,6 +54,20 @@
return bytes;
}
+BytesPtr
+ParsedContentObject::contentPtr() const
+{
+ const unsigned char *content;
+ size_t len;
+ int res = ccn_content_get_value(head(m_bytes), m_pco.offset[CCN_PCO_E], &m_pco, &content, &len);
+ if (res < 0)
+ {
+ boost::throw_exception(MisformedContentObjectException());
+ }
+
+ return readRawPtr (content, len);
+}
+
Name
ParsedContentObject::name() const
{
diff --git a/src/ccnx-wrapper.cpp b/src/ccnx-wrapper.cpp
index b6902a8..3f82889 100644
--- a/src/ccnx-wrapper.cpp
+++ b/src/ccnx-wrapper.cpp
@@ -16,22 +16,6 @@
namespace Ccnx {
-void
-readRaw(Bytes &bytes, const unsigned char *src, size_t len)
-{
- if (len > 0)
- {
- bytes.resize(len);
- memcpy(&bytes[0], src, len);
- }
-}
-
-const unsigned char *
-head(const Bytes &bytes)
-{
- return &bytes[0];
-}
-
CcnxWrapper::CcnxWrapper()
: m_handle (0)
, m_running (true)
diff --git a/src/object-db.cc b/src/object-db.cc
index 8cadf7e..0d1a2a6 100644
--- a/src/object-db.cc
+++ b/src/object-db.cc
@@ -39,6 +39,7 @@
\
PRIMARY KEY (device_name, segment) \n\
); \n\
+CREATE INDEX device ON File(device_name); \n\
";
ObjectDb::ObjectDb (const fs::path &folder, const std::string &hash)
@@ -61,11 +62,50 @@
res = sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, &errmsg);
if (res != SQLITE_OK && errmsg != 0)
{
- std::cerr << "DEBUG: " << errmsg << std::endl;
+ // std::cerr << "DEBUG: " << errmsg << std::endl;
sqlite3_free (errmsg);
}
}
+bool
+ObjectDb::DoesExist (const boost::filesystem::path &folder, const Ccnx::Name &deviceName, const std::string &hash)
+{
+ fs::path actualFolder = folder / "objects" / hash.substr (0, 2);
+ bool retval = false;
+
+ sqlite3 *db;
+ int res = sqlite3_open((actualFolder / hash.substr (2, hash.size () - 2)).c_str (), &db);
+ if (res == SQLITE_OK)
+ {
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (db, "SELECT count(*), count(nullif(content_object,0)) FROM File WHERE device_name=?", -1, &stmt, 0);
+
+ CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
+ sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
+
+ int res = sqlite3_step (stmt);
+ if (res == SQLITE_ROW)
+ {
+ int countAll = sqlite3_column_int (stmt, 0);
+ int countNonNull = sqlite3_column_int (stmt, 1);
+
+ cout << countAll << ", " << countNonNull << endl;
+
+ if (countAll > 0 && countAll==countNonNull)
+ {
+ cout << "2" << endl;
+ retval = true;
+ }
+ }
+
+ sqlite3_finalize (stmt);
+ }
+
+ sqlite3_close (db);
+ return retval;
+}
+
+
ObjectDb::~ObjectDb ()
{
int res = sqlite3_close (m_db);
@@ -83,6 +123,8 @@
"(device_name, segment, content_object) "
"VALUES (?, ?, ?)", -1, &stmt, 0);
+ cout << deviceName << endl;
+
CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, segment);
@@ -118,7 +160,20 @@
return ret;
}
+
// sqlite3_int64
// ObjectDb::getNumberOfSegments (const Ccnx::Name &deviceName)
// {
+// sqlite3_stmt *stmt;
+// sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM File WHERE device_name=?", -1, &stmt, 0);
+
+// bool retval = false;
+// int res = sqlite3_step (stmt);
+// if (res == SQLITE_ROW)
+// {
+// retval = true;
+// }
+// sqlite3_finalize (stmt);
+
+// return retval;
// }
diff --git a/src/object-db.h b/src/object-db.h
index 9e824de..9ecd753 100644
--- a/src/object-db.h
+++ b/src/object-db.h
@@ -43,6 +43,9 @@
// sqlite3_int64
// getNumberOfSegments (const Ccnx::Name &deviceName);
+
+ static bool
+ DoesExist (const boost::filesystem::path &folder, const Ccnx::Name &deviceName, const std::string &hash);
private:
sqlite3 *m_db;
diff --git a/src/object-manager.cc b/src/object-manager.cc
index a2de9f1..7f66b2a 100644
--- a/src/object-manager.cc
+++ b/src/object-manager.cc
@@ -22,6 +22,7 @@
#include "object-manager.h"
#include "ccnx-name.h"
#include "ccnx-common.h"
+#include "ccnx-pco.h"
#include "object-db.h"
#include <sys/stat.h>
@@ -29,6 +30,7 @@
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/throw_exception.hpp>
+#include <boost/filesystem/fstream.hpp>
using namespace Ccnx;
using namespace boost;
@@ -37,9 +39,8 @@
const int MAX_FILE_SEGMENT_SIZE = 1024;
-ObjectManager::ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const fs::path &folder)
+ObjectManager::ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const fs::path &folder)
: m_ccnx (ccnx)
- , m_localDeviceName (localDeviceName)
, m_folder (folder / ".chronoshare")
{
fs::create_directories (m_folder);
@@ -50,30 +51,64 @@
}
HashPtr
-ObjectManager::storeLocalFile (const fs::path &file)
+ObjectManager::localFileToObjects (const fs::path &file, const Ccnx::Name &deviceName)
{
HashPtr fileHash = Hash::FromFileContent (file);
ObjectDb fileDb (m_folder, lexical_cast<string> (*fileHash));
- ifstream iff (file.c_str (), std::ios::in | std::ios::binary);
- int segment = 0;
+ fs::ifstream iff (file, std::ios::in | std::ios::binary);
+ sqlite3_int64 segment = 0;
while (iff.good ())
{
char buf[MAX_FILE_SEGMENT_SIZE];
iff.read (buf, MAX_FILE_SEGMENT_SIZE);
-
- Name name (m_localDeviceName);
+ Name name (deviceName);
name
.appendComp ("file")
.appendComp (fileHash->GetHash (), fileHash->GetHashBytes ())
.appendComp (segment);
- cout << *fileHash << endl;
- cout << name << endl;
+ // cout << *fileHash << endl;
+ // cout << name << endl;
+
+ Bytes data = m_ccnx->createContentObject (name, buf, iff.gcount ());
+ fileDb.saveContentObject (deviceName, segment, data);
segment ++;
}
return fileHash;
}
+
+bool
+ObjectManager::objectsToLocalFile (/*in*/const Ccnx::Name &deviceName, /*in*/const Hash &fileHash, /*out*/ const fs::path &file)
+{
+ string hashStr = lexical_cast<string> (fileHash);
+ if (!ObjectDb::DoesExist (m_folder, deviceName, hashStr))
+ {
+ cout << "Brr" << endl;
+ // file does not exist or not all segments are available
+ return false;
+ }
+
+ fs::ofstream off (file, std::ios::out | std::ios::binary);
+ ObjectDb fileDb (m_folder, hashStr);
+
+ sqlite3_int64 segment = 0;
+ BytesPtr bytes = fileDb.fetchSegment (deviceName, 0);
+ while (bytes != BytesPtr())
+ {
+ ParsedContentObject obj (*bytes);
+ BytesPtr data = obj.contentPtr ();
+
+ off.write (reinterpret_cast<const char*> (head(*data)), data->size());
+
+ segment ++;
+ bytes = fileDb.fetchSegment (deviceName, segment);
+ }
+
+ // permission and timestamp should be assigned somewhere else (ObjectManager has no idea about that)
+
+ return true;
+}
diff --git a/src/object-manager.h b/src/object-manager.h
index 4ae719b..f0cd6e6 100644
--- a/src/object-manager.h
+++ b/src/object-manager.h
@@ -32,15 +32,17 @@
class ObjectManager
{
public:
- ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const boost::filesystem::path &folder);
+ ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &folder);
virtual ~ObjectManager ();
HashPtr
- storeLocalFile (const boost::filesystem::path &file);
+ localFileToObjects (const boost::filesystem::path &file, const Ccnx::Name &deviceName);
+
+ bool
+ objectsToLocalFile (/*in*/const Ccnx::Name &deviceName, /*in*/const Hash &hash, /*out*/ const boost::filesystem::path &file);
private:
Ccnx::CcnxWrapperPtr m_ccnx;
- Ccnx::Name m_localDeviceName;
boost::filesystem::path m_folder;
};