blob: d9000988d356c9596b1b8e08e972c222d02032ec [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2017, Regents of the University of California.
*
* This file is part of ChronoShare, a decentralized file sharing application over NDN.
*
* ChronoShare is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* ChronoShare 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 copies of the GNU General Public License along with
* ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ChronoShare authors and contributors.
*/
#include "object-manager.hpp"
#include "ccnx-common.hpp"
#include "ccnx-name.hpp"
#include "ccnx-pco.hpp"
#include "logging.hpp"
#include "object-db.hpp"
#include <sys/stat.h>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/throw_exception.hpp>
#include <fstream>
_LOG_INIT(Object.Manager);
using namespace Ndnx;
using namespace boost;
using namespace std;
namespace fs = boost::filesystem;
const int MAX_FILE_SEGMENT_SIZE = 1024;
ObjectManager::ObjectManager(Ccnx::CcnxWrapperPtr ccnx, const fs::path& folder,
const std::string& appName)
: m_ccnx(ccnx)
, m_folder(folder / ".chronoshare")
, m_appName(appName)
{
fs::create_directories(m_folder);
}
ObjectManager::~ObjectManager()
{
}
// /<devicename>/<appname>/file/<hash>/<segment>
boost::tuple<HashPtr /*object-db name*/, size_t /* number of segments*/>
ObjectManager::localFileToObjects(const fs::path& file, const Ccnx::Name& deviceName)
{
HashPtr fileHash = Hash::FromFileContent(file);
ObjectDb fileDb(m_folder, lexical_cast<string>(*fileHash));
fs::ifstream iff(file, std::ios::in | std::ios::binary);
sqlite3_int64 segment = 0;
while (iff.good() && !iff.eof()) {
char buf[MAX_FILE_SEGMENT_SIZE];
iff.read(buf, MAX_FILE_SEGMENT_SIZE);
if (iff.gcount() == 0) {
// stupid streams...
break;
}
Name name = Name("/")(deviceName)(m_appName)("file")(fileHash->GetHash(),
fileHash->GetHashBytes())(segment);
// cout << *fileHash << endl;
// cout << name << endl;
//_LOG_DEBUG ("Read " << iff.gcount () << " from " << file << " for segment " << segment);
Bytes data = m_ccnx->createContentObject(name, buf, iff.gcount());
fileDb.saveContentObject(deviceName, segment, data);
segment++;
}
if (segment == 0) // handle empty files
{
Name name =
Name("/")(m_appName)("file")(fileHash->GetHash(), fileHash->GetHashBytes())(deviceName)(0);
Bytes data = m_ccnx->createContentObject(name, 0, 0);
fileDb.saveContentObject(deviceName, 0, data);
segment++;
}
return make_tuple(fileHash, segment);
}
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)) {
_LOG_ERROR("ObjectDb for [" << m_folder << ", " << deviceName << ", " << hashStr
<< "] does not exist or not all segments are available");
return false;
}
if (!exists(file.parent_path())) {
create_directories(file.parent_path());
}
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) {
ParsedContentObject obj(*bytes);
BytesPtr data = obj.contentPtr();
if (data) {
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;
}