Initial stuff for sqllite version of object-db. Changing to boost::filesystem
diff --git a/src/action-item.proto b/src/action-item.proto
index 0144a22..3218ef8 100644
--- a/src/action-item.proto
+++ b/src/action-item.proto
@@ -12,9 +12,9 @@
   required uint32 timestamp = 6;
 
   optional bytes  file_hash = 7;
-  optional uint32 atime = 8;
+  // optional uint32 atime = 8;
   optional uint32 mtime = 9;
-  optional uint32 ctime = 10;
+  // optional uint32 ctime = 10;
   optional uint32 mode  = 11;
 
   optional bytes  parent_device_name = 12;
diff --git a/src/action-log.cc b/src/action-log.cc
index 5456362..cc0d945 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -26,7 +26,8 @@
 using namespace std;
 using namespace Ccnx;
 
-ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const std::string &path, const std::string &localName, const std::string &sharedFolder)
+ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
+                      const std::string &localName, const std::string &sharedFolder)
   : SyncLog (path, localName)
   , m_ccnx (ccnx)
   , m_sharedFolderName (sharedFolder)
@@ -83,7 +84,7 @@
 void
 ActionLog::AddActionUpdate (const std::string &filename,
                             const Hash &hash,
-                            time_t atime, time_t mtime, time_t ctime,
+                            time_t wtime,
                             int mode)
 {
   sqlite3_exec (m_db, "BEGIN TRANSACTION;", 0,0,0);
@@ -135,9 +136,9 @@
   
   sqlite3_bind_blob  (stmt, 7, hash.GetHash (), hash.GetHashBytes (), SQLITE_TRANSIENT);
   
-  sqlite3_bind_int64 (stmt, 8, atime);
-  sqlite3_bind_int64 (stmt, 9, mtime);
-  sqlite3_bind_int64 (stmt, 10, ctime);
+  // sqlite3_bind_int64 (stmt, 8, atime); // NULL
+  sqlite3_bind_int64 (stmt, 9, wtime);
+  // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
   sqlite3_bind_int   (stmt, 11, mode);
 
   if (parent_device_id > 0 && parent_seq_no > 0)
@@ -159,9 +160,9 @@
   item.set_version (version);
   item.set_timestamp (action_time);
   item.set_file_hash (hash.GetHash (), hash.GetHashBytes ());
-  item.set_atime (atime);
-  item.set_mtime (mtime);
-  item.set_ctime (ctime);
+  // item.set_atime (atime);
+  item.set_mtime (wtime);
+  // item.set_ctime (ctime);
   item.set_mode (mode);
 
   if (parent_device_id > 0 && parent_seq_no > 0)
diff --git a/src/action-log.h b/src/action-log.h
index 323f6a3..7d778d8 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -32,12 +32,13 @@
 class ActionLog : public SyncLog
 {
 public:
-  ActionLog (Ccnx::CcnxWrapperPtr ccnx, const std::string &path, const std::string &localName, const std::string &sharedFolder);
+  ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
+             const std::string &localName, const std::string &sharedFolder);
 
   void
   AddActionUpdate (const std::string &filename,
                    const Hash &hash,
-                   time_t atime, time_t mtime, time_t ctime,
+                   time_t wtime,
                    int mode);
 
   void
diff --git a/src/chronoshare-client.ice b/src/chronoshare-client.ice
index e3bf8e2..c2e056f 100644
--- a/src/chronoshare-client.ice
+++ b/src/chronoshare-client.ice
@@ -25,7 +25,7 @@
   
   interface Notify 
   {
-    void updateFile (string filename, ["cpp:array"] HashBytes fileHash, long atime, long mtime, long ctime, int mode);
+    void updateFile (string filename, ["cpp:array"] HashBytes fileHash, long wtime, int mode);
 
     void moveFile (string origFilename, string newFilename);
 
diff --git a/src/db-helper.cc b/src/db-helper.cc
index 217c3ee..c5455e8 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -26,6 +26,7 @@
 #include <boost/throw_exception.hpp>
 
 using namespace boost;
+namespace fs = boost::filesystem;
 
 const std::string INIT_DATABASE = "\
 PRAGMA foreign_keys = ON;                                       \n\
@@ -162,13 +163,16 @@
 CREATE INDEX FileState_device_id_seq_no ON FileState (device_id, seq_no); \n\
 ";
 
-DbHelper::DbHelper (const std::string &path)
+DbHelper::DbHelper (const fs::path &path)
 {
-  int res = sqlite3_open((path+"chronoshare.db").c_str (), &m_db);
+  fs::path chronoshareDirectory = path / ".chronoshare";
+  fs::create_directories (chronoshareDirectory);
+  
+  int res = sqlite3_open((chronoshareDirectory / "state.db").c_str (), &m_db);
   if (res != SQLITE_OK)
     {
       BOOST_THROW_EXCEPTION (Error::Db ()
-                             << errmsg_info_str ("Cannot open/create dabatabase: [" + path + "chronoshare.db" + "]"));
+                             << errmsg_info_str ("Cannot open/create dabatabase: [" + (chronoshareDirectory / "state.db").string () + "]"));
     }
   
   res = sqlite3_create_function (m_db, "hash", 2, SQLITE_ANY, 0, 0,
diff --git a/src/db-helper.h b/src/db-helper.h
index 51970dd..a32df64 100644
--- a/src/db-helper.h
+++ b/src/db-helper.h
@@ -28,13 +28,14 @@
 #include <boost/exception/all.hpp>
 #include <string>
 #include "hash-helper.h"
+#include <boost/filesystem.hpp>
 
 typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str; 
 
 class DbHelper
 {
 public:
-  DbHelper (const std::string &path);
+  DbHelper (const boost::filesystem::path &path);
   virtual ~DbHelper ();
   
 private:
diff --git a/src/hash-helper.cc b/src/hash-helper.cc
index 33c0e77..dbb70a3 100644
--- a/src/hash-helper.cc
+++ b/src/hash-helper.cc
@@ -33,11 +33,12 @@
 #include <boost/archive/iterators/transform_width.hpp>
 #include <boost/iterator/transform_iterator.hpp>
 #include <boost/archive/iterators/dataflow_exception.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 using namespace boost;
 using namespace boost::archive::iterators;
 using namespace std;
-
+namespace fs = boost::filesystem;
 
 template<class CharType>
 struct hex_from_4_bit
@@ -130,7 +131,7 @@
 }
 
 HashPtr
-Hash::FromFileContent (const std::string &filename)
+Hash::FromFileContent (const fs::path &filename)
 {
   HashPtr retval = make_shared<Hash> (reinterpret_cast<void*> (0), 0);
   retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
@@ -138,7 +139,7 @@
   EVP_MD_CTX *hash_context = EVP_MD_CTX_create ();
   EVP_DigestInit_ex (hash_context, HASH_FUNCTION (), 0);
 
-  ifstream iff (filename.c_str (), std::ios::in | std::ios::binary);
+  fs::ifstream iff (filename, std::ios::in | std::ios::binary);
   while (iff.good ())
     {
       char buf[1024];
diff --git a/src/hash-helper.h b/src/hash-helper.h
index ea12f30..d4f750d 100644
--- a/src/hash-helper.h
+++ b/src/hash-helper.h
@@ -26,6 +26,7 @@
 #include <iostream>
 #include <boost/shared_ptr.hpp>
 #include <boost/exception/all.hpp>
+#include <boost/filesystem.hpp>
 
 // Other options: VP_md2, EVP_md5, EVP_sha, EVP_sha1, EVP_sha256, EVP_dss, EVP_dss1, EVP_mdc2, EVP_ripemd160
 #define HASH_FUNCTION EVP_sha256
@@ -50,7 +51,7 @@
   FromString (const std::string &hashInTextEncoding);
 
   static HashPtr
-  FromFileContent (const std::string &hashInTextEncoding);
+  FromFileContent (const boost::filesystem::path &fileName);
   
   ~Hash ()
   {
diff --git a/src/object-db-file.cpp b/src/object-db-file.cpp
deleted file mode 100644
index 26f8fb3..0000000
--- a/src/object-db-file.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-#include "object-db-file.h"
-#include <assert.h>
-
-char *
-head(const Bytes &bytes)
-{
-  return (char *)&bytes[0];
-}
-
-void
-writeBytes(ostream &out, const Bytes &bytes)
-{
-  int size = bytes.size();
-  writeInt(out, size);
-  out.write(head(bytes), size);
-}
-
-void
-readBytes(istream &in, Bytes &bytes)
-{
-  int size;
-  readInt(in, size);
-  bytes.reserve(size);
-  in.read(head(bytes), size);
-}
-
-ObjectDBFile::ObjectDBFile(const string &filename)
-                : m_size(0)
-                , m_cap(0)
-                , m_index(0)
-                , m_initialized(false)
-                , m_filename(filename)
-                // This ensures file with filename exists (assuming having write permission)
-                // This is needed as file_lock only works with existing file
-                , m_ostream(m_filename.c_str(), ios_base::binary | ios_base::app)
-                , m_istream(m_filename.c_str(), ios_base::binary | ios_base::binary)
-                , m_filelock(m_filename.c_str())
-{
-  int magic;
-  ReadLock(m_filelock);
-  readInt(m_istream, magic);
-  if (magic == MAGIC_NUM)
-  {
-    m_initialized = true;
-    readInt(m_istream, m_cap);
-    readInt(m_istream, m_size);
-    m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
-  }
-}
-
-ObjectDBFile::~ObjectDBFile()
-{
-  m_istream.close();
-  m_ostream.close();
-}
-
-void
-ObjectDBFile::init(int capacity)
-{
-  WriteLock(*m_filelock);
-  if (m_initialized)
-  {
-    throwException("Trying to init already initialized ObjectDBFile object" + m_filename);
-  }
-
-  m_cap = capacity;
-  m_size = 0;
-
-  int magic = MAGIC_NUM;
-  writeInt(m_ostream, magic);
-  writeInt(m_ostream, m_cap);
-  writeInt(m_ostream, m_size);
-  m_initialized = true;
-
-  int count = m_cap;
-  int offset = 0;
-  while (count-- > 0)
-  {
-    writeInt(m_ostream, offset);
-  }
-
-  // prepare read pos
-  m_istream.seekg(m_ostream.tellp(), ios::beg);
-
-  // DEBUG
-  assert(m_ostream.tellp() == ((3 + m_cap) * sizeof(int)));
-
-}
-
-// Append is not super efficient as it needs to seek and update the pos for the
-// Content object. However, in our app, it is the case the these objects are wrote
-// once and read multiple times, so it's not a big problem.
-void
-ObjectDBFile::append(const Bytes &co)
-{
-  WriteLock(m_filelock);
-  checkInit("Trying to append to un-initialized ObjectDBFile: " + m_filename);
-
-  if (m_size >= m_cap)
-  {
-    throwException("Exceed Maximum capacity: " + boost::lexical_cast<string>(m_cap));
-  }
-
-  // pos for this CO
-  int coPos = m_ostream.tellp();
-  // index field for this CO
-  int indexPos = (3 + m_size) * sizeof(int);
-
-  m_size++;
-
-  // Update size (is it necessary?) We'll do it for now anyway
-  m_ostream.seekp( 2 * sizeof(int), ios::beg);
-  writeInt(m_ostream, m_size);
-
-  // Write the pos for the CO
-  m_ostream.seekp(indexPos, ios::beg);
-  writeInt(m_ostream, coPos);
-
-  // write the content object
-  m_ostream.seekp(coPos, ios::beg);
-  writeBytes(m_ostream, co);
-
-  // By the end, the write pos is at the end of the file
-}
-
-// forget about caching for now; but ideally, we should cache the next few COs in memory
-// and the request for COs tends to be sequential
-Bytes
-ObjectDBFile::next()
-{
-  // Scoped shared lock for cache
-  {
-    SLock(m_cacheLock);
-    // no need to read file if found in cache
-    if (m_dummyCache.find(m_index) != m_dummyCache.end())
-    {
-      int index = m_index;
-      m_index++;
-      return m_dummyCache[index];
-    }
-  }
-
-  ReadLock(m_filelock);
-
-  // m_index not found in cache
-  Bytes co;
-  if (m_index >= m_size)
-  {
-    // at the end of file, return empty
-    return co;
-  }
-
-  readBytes(m_istream, co);
-  m_index++;
-
-  // fill dummy cache with the next CACHE_SIZE COs
-  fillDummyCache();
-
-  return co;
-}
-
-void
-ObjectDBFile::fillDummyCache()
-{
-  ULock(m_cacheLock);
-  m_dummyCache.clear();
-  int stop = (m_index + CACHE_SIZE < m_size) ? m_index + CACHE_SIZE : m_size;
-  // the m_index should not change
-  int index = m_index;
-  while (index < stop)
-  {
-    Bytes co;
-    readBytes(m_istream, co);
-    m_dummyCache.insert(make_pair(index, co));
-    index++;
-  }
-}
-
-int
-ObjectDBFile::size() const
-{
-  return m_size;
-}
-
-void
-ObjectDBFile::updateSize()
-{
-  int pos = m_istream.tellg();
-  m_istream.seekg(2 * sizeof(int), ios::beg);
-  readInt(m_istream, m_size);
-  // recover the original pos
-  m_istream.seekg(pos, ios::beg);
-}
-
-int
-ObjectDBFile::fSize()
-{
-  ReadLock(m_filelock);
-  updateSize();
-  return m_size;
-}
-
-int
-ObjectDBFile::index()
-{
-  ReadLock(m_filelock);
-  return m_index;
-}
-
-bool
-ObjectDBFile::seek(int index)
-{
-  ReadLock(m_filelock);
-  updateSize();
-  if (m_size <= index)
-  {
-    return false;
-  }
-  m_index = index;
-  m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
-  int pos;
-  readInt(m_istream, pos);
-  m_istream.seekg(pos, ios::beg);
-  return true;
-}
-
-void
-ObjectDBFile::rewind()
-{
-  ReadLock(m_filelock);
-  m_index = 0;
-  // point to the start of the CO fields
-  m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
-}
-
-void
-ObjectDBFile::checkInit(const string &msg)
-{
-  if (!m_initialized)
-  {
-    throwException(msg);
-  }
-}
diff --git a/src/object-db-file.h b/src/object-db-file.h
deleted file mode 100644
index 1eb1ef8..0000000
--- a/src/object-db-file.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef OBJECT_DB_FILE_H
-#define OBJECT_DB_FILE_H
-
-#include "object-db.h"
-#include <stdio.h>
-#include <fstream>
-#include <sstream>
-#include <deque>
-#include <boost/thread/locks.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/thread/shared_mutex.hpp>
-#include <boost/interprocess/sync/file_lock.hpp>
-#include <boost/interprocess/sync/sharable_lock.hpp>
-#include <boost/interprocess/sync/scoped_lock.hpp>
-
-#define _OVERRIDE
-#ifdef __GNUC__
-#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
-  #undef _OVERRIDE
-  #define _OVERRIDE override
-#endif // __GNUC__ version
-#endif // __GNUC__
-
-using namespace std;
-
-// This is a file based ObjectDB implementation
-// The assumption is, the Content Objects will be stored sequentially
-
-// To provide random access, we will have a table of "address" for each
-// ContentObject at the beginning of the file.
-// This also requires another assumption, that is the number of COs must
-// be know a priori. This requirement is reasonable for our dropbox-like
-// System, as the file we publish is static file and we can easily know
-// the number of COs before we store them into ObjectDB.
-
-/* How file looks like:
- * |MAGIC_NUM|capacity|size|pos for each CO ...|1st CO|2nd CO| ... |
- */
-
-class ObjectDBFile
-{
-public:
-  typedef boost::interprocess::file_lock Filelock;
-  typedef boost::interprocess::scoped_lock<Filelock> WriteLock;
-  typedef boost::interprocess::sharable_lock<Filelock> ReadLock;
-  typedef boost::shared_mutex Mutex;
-  typedef boost::shared_lock<Mutex> SLock;
-  typedef boost::unique_lock<Mutex> ULock;
-
-  ObjectDBFile(const string &filename);
-  virtual ~ObjectDBFile();
-
-  // reserve the "address" table for n COs; must reserve before
-  // write anything (unless reserved quota has not be consumed yet)
-  void
-  init(int capacity);
-
-  bool
-  initialized() const { return m_initialized; }
-
-  // assume sequential
-  virtual void
-  append(const Bytes &co) _OVERRIDE;
-
-  // get next CO
-  virtual Bytes
-  next() _OVERRIDE;
-
-  // size in terms of number of COs
-  // This is the lazy form of size, i.e. it returns the size cached in this object
-  // but that may not necessarily equal to the actual size kept in file
-  // This is enough if the caller knows for sure that no other thread is changing the
-  // file or the caller does not care about the new size.
-  virtual int
-  size() const _OVERRIDE;
-
-  // this returns the actual size (also update the size cache in this object), but it is more costly, and requires file IO
-  int
-  fSize();
-
-  // the index of the CO to be read
-  int
-  index();
-
-  // set the pos to be the desired CO
-  // return true if success
-  bool
-  seek(int index);
-
-  // reset pos to be zero
-  void
-  rewind();
-
-protected:
-  // read or write lock should have been grabbed already before the call
-  void
-  checkInit(const string &msg);
-
-  // read lock should have been grabbed already before the call
-  void
-  updateSize();
-
-  // read lock should have been grabbed already before the call
-  void
-  fillDummyCache();
-
-  #define MAGIC_NUM 0xAAAAAAAA
-
-protected:
-  string m_filename;
-  ifstream m_istream;
-  ofstream m_ostream;
-  Filelock m_filelock;
-  bool m_initialized;
-  // capacity in terms of number of COs
-  int m_cap;
-  int m_size;
-  // the index (or seq) of the CO to be read
-  int m_index;
-
-  // A dummy Cache that holds the next 10 (or all remaining if less than 10)
-  // COs after a next() operation
-  // If needed and time allows, we can have more complex cache
-  #define CACHE_SIZE 10
-  map<int, Bytes> m_dummyCache;
-  Mutex m_cacheMutex;
-};
-
-void inline
-writeInt(ostream &out, const int &x)
-{
-  out.write((const char *)&x, sizeof(int));
-}
-
-void inline
-readInt(istream &in, int &x)
-{
-  in.read((char *)&x, sizeof(int));
-}
-
-// write size and then the actual bytes
-// operator << overloading is not used to avoid confusion
-void
-writeBytes(ostream &out, const Bytes &bytes);
-
-// read size and then the actual bytes
-void
-readBytes(istream &in, Bytes &bytes);
-
-char *
-head(const Bytes &bytes);
-
-#endif
diff --git a/src/object-db.cc b/src/object-db.cc
new file mode 100644
index 0000000..8cadf7e
--- /dev/null
+++ b/src/object-db.cc
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program 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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "object-db.h"
+#include <iostream>
+#include <boost/make_shared.hpp>
+#include "db-helper.h"
+#include <sys/stat.h>
+
+using namespace std;
+using namespace Ccnx;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+const std::string INIT_DATABASE = "\
+CREATE TABLE                                                            \n\
+    File(                                                               \n\
+        device_name     BLOB NOT NULL,                                  \n\
+        segment         INTEGER,                                        \n\
+        content_object  BLOB,                                           \n\
+                                                                        \
+        PRIMARY KEY (device_name, segment)                              \n\
+    );                                                                  \n\
+";
+
+ObjectDb::ObjectDb (const fs::path &folder, const std::string &hash)
+{
+  fs::path actualFolder = folder / "objects" / hash.substr (0, 2);
+  fs::create_directories (actualFolder);
+  
+  int res = sqlite3_open((actualFolder / hash.substr (2, hash.size () - 2)).c_str (), &m_db);
+  if (res != SQLITE_OK)
+    {
+      BOOST_THROW_EXCEPTION (Error::Db ()
+                             << errmsg_info_str ("Cannot open/create dabatabase: [" +
+                                                 (actualFolder / hash.substr (2, hash.size () - 2)).string () + "]"));
+    }
+  
+  // Alex: determine if tables initialized. if not, initialize... not sure what is the best way to go...
+  // for now, just attempt to create everything
+
+  char *errmsg = 0;
+  res = sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, &errmsg);
+  if (res != SQLITE_OK && errmsg != 0)
+    {
+      std::cerr << "DEBUG: " << errmsg << std::endl;
+      sqlite3_free (errmsg);
+    }  
+}
+
+ObjectDb::~ObjectDb ()
+{
+  int res = sqlite3_close (m_db);
+  if (res != SQLITE_OK)
+    {
+      // complain
+    }
+}
+
+void
+ObjectDb::saveContentObject (const Ccnx::Name &deviceName, sqlite3_int64 segment, const Ccnx::Bytes &data)
+{
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "INSERT INTO File "
+                      "(device_name, segment, content_object) "
+                      "VALUES (?, ?, ?)", -1, &stmt, 0);
+
+  CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
+  sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
+  sqlite3_bind_int64 (stmt, 2, segment);
+  sqlite3_bind_blob (stmt, 3, &data[0], data.size (), SQLITE_TRANSIENT);
+
+  sqlite3_step (stmt);
+  sqlite3_finalize (stmt);
+}
+
+Ccnx::BytesPtr
+ObjectDb::fetchSegment (const Ccnx::Name &deviceName, sqlite3_int64 segment)
+{
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT content_object FROM File WHERE device_name=? AND segment=?", -1, &stmt, 0);
+
+  CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
+  sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
+  sqlite3_bind_int64 (stmt, 2, segment);
+
+  BytesPtr ret;
+  
+  int res = sqlite3_step (stmt);
+  if (res == SQLITE_ROW)
+    {
+      const unsigned char *buf = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (stmt, 0));
+      int bufBytes = sqlite3_column_bytes (stmt, 0);
+
+      ret = make_shared<Bytes> (buf, buf+bufBytes);
+    }
+
+  sqlite3_finalize (stmt);
+
+  return ret;
+}
+
+// sqlite3_int64
+// ObjectDb::getNumberOfSegments (const Ccnx::Name &deviceName)
+// {
+// }
diff --git a/src/object-db.h b/src/object-db.h
index 8c31418..9e824de 100644
--- a/src/object-db.h
+++ b/src/object-db.h
@@ -1,42 +1,51 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program 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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
 #ifndef OBJECT_DB_H
 #define OBJECT_DB_H
 
-#include <boost/exception/all.hpp>
-#include <vector>
+#include <string>
+#include <sqlite3.h>
+#include <ccnx-common.h>
+#include <ccnx-name.h>
+#include <boost/filesystem.hpp>
 
-using namespace std;
-
-struct ObjectDBException : virtual boost::exception, virtual exception { };
-typedef boost::error_info<struct tag_errmsg, std::string> error_info_str;
-
-inline void throwException(const string &msg) { boost::throw_exception(ObjectDBException() << error_info_str(msg)); }
-
-typedef unsigned char Byte;
-typedef vector<Byte> Bytes;
-
-// OK. This name is a bit miss-leading, but this ObjectDB is really some storage
-// that stores the Ccnx ContentObjects of a file. So unlike a normal database,
-// this DB is per file.
-
-// The assumption is, the ContentObjects will be write to ObjectDB sequentially
-// This guarantees that when read, the Nth ContentObject read has the sequence number N as the last component of its name
-class ObjectDB
+class ObjectDb
 {
 public:
-  virtual ~ObjectDB(){}
+  // database will be create in <folder>/<first-pair-of-hash-bytes>/<rest-of-hash>
+  ObjectDb (const boost::filesystem::path &folder, const std::string &hash);
+  ~ObjectDb ();
 
-  // assume sequential
-  virtual void
-  append(const Bytes &co) = 0;
+  void
+  saveContentObject (const Ccnx::Name &deviceName, sqlite3_int64 segment, const Ccnx::Bytes &data);
 
-  // get next CO
-  virtual Bytes
-  next() = 0;
+  Ccnx::BytesPtr
+  fetchSegment (const Ccnx::Name &deviceName, sqlite3_int64 segment);
 
-  // size in terms of number of COs
-  virtual int
-  size() = 0;
-
+  // sqlite3_int64
+  // getNumberOfSegments (const Ccnx::Name &deviceName);
+  
+private:
+  sqlite3 *m_db;
 };
 
-#endif
+#endif // OBJECT_DB_H
diff --git a/src/object-manager.cc b/src/object-manager.cc
new file mode 100644
index 0000000..a2de9f1
--- /dev/null
+++ b/src/object-manager.cc
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program 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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "object-manager.h"
+#include "ccnx-name.h"
+#include "ccnx-common.h"
+#include "object-db.h"
+
+#include <sys/stat.h>
+
+#include <fstream>
+#include <boost/lexical_cast.hpp>
+#include <boost/throw_exception.hpp>
+
+using namespace Ccnx;
+using namespace boost;
+using namespace std;
+namespace fs = boost::filesystem;
+
+const int MAX_FILE_SEGMENT_SIZE = 1024;
+
+ObjectManager::ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const fs::path &folder)
+  : m_ccnx (ccnx)
+  , m_localDeviceName (localDeviceName)
+  , m_folder (folder / ".chronoshare")
+{
+  fs::create_directories (m_folder);
+}
+
+ObjectManager::~ObjectManager ()
+{
+}
+
+HashPtr
+ObjectManager::storeLocalFile (const fs::path &file)
+{
+  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;
+  while (iff.good ())
+    {
+      char buf[MAX_FILE_SEGMENT_SIZE];
+      iff.read (buf, MAX_FILE_SEGMENT_SIZE);
+
+
+      Name name (m_localDeviceName);
+      name
+        .appendComp ("file")
+        .appendComp (fileHash->GetHash (), fileHash->GetHashBytes ())
+        .appendComp (segment);
+
+      cout << *fileHash << endl;
+      cout << name << endl;
+      
+      segment ++;
+    }
+  
+  return fileHash;
+}
diff --git a/src/object-manager.h b/src/object-manager.h
new file mode 100644
index 0000000..4ae719b
--- /dev/null
+++ b/src/object-manager.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2013 University of California, Los Angeles
+ *
+ * This program 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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef OBJECT_MANAGER_H
+#define OBJECT_MANAGER_H
+
+#include <string>
+#include <ccnx-wrapper.h>
+#include <hash-helper.h>
+#include <boost/filesystem.hpp>
+
+// everything related to managing object files
+
+class ObjectManager
+{
+public:
+  ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const boost::filesystem::path &folder);
+  virtual ~ObjectManager ();
+
+  HashPtr
+  storeLocalFile (const boost::filesystem::path &file);
+  
+private:
+  Ccnx::CcnxWrapperPtr m_ccnx;
+  Ccnx::Name m_localDeviceName;
+  boost::filesystem::path m_folder;
+};
+
+typedef boost::shared_ptr<ObjectManager> ObjectManagerPtr;
+
+namespace Error {
+struct ObjectManager : virtual boost::exception, virtual std::exception { };
+}
+
+#endif // OBJECT_MANAGER_H
diff --git a/src/sync-log.cc b/src/sync-log.cc
index ce5b46c..ca6adf7 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -26,7 +26,7 @@
 using namespace boost;
 using namespace std;
 
-SyncLog::SyncLog (const std::string &path, const std::string &localName)
+SyncLog::SyncLog (const boost::filesystem::path &path, const std::string &localName)
   : DbHelper (path)
   , m_localName (localName)
 {
diff --git a/src/sync-log.h b/src/sync-log.h
index 0316294..c75fcf7 100644
--- a/src/sync-log.h
+++ b/src/sync-log.h
@@ -31,7 +31,7 @@
 class SyncLog : public DbHelper
 {
 public:
-  SyncLog (const std::string &path, const std::string &localName);
+  SyncLog (const boost::filesystem::path &path, const std::string &localName);
 
   sqlite3_int64
   GetNextLocalSeqNo (); // side effect: local seq_no will be increased