Deletion detection
diff --git a/cmd/csd.cc b/cmd/csd.cc
index 3259e7a..a1d4d41 100644
--- a/cmd/csd.cc
+++ b/cmd/csd.cc
@@ -53,8 +53,8 @@
FsWatcher watcher (path.c_str (),
bind (&Dispatcher::Did_LocalFile_AddOrModify, &dispatcher, _1),
- bind (&Dispatcher::Did_LocalFile_Delete, &dispatcher, _1));
-
+ bind (&Dispatcher::Did_LocalFile_Delete, &dispatcher, _1),
+ dispatcher.GetFileState ());
return app.exec ();
}
diff --git a/cmd/dump-db.cc b/cmd/dump-db.cc
index 568c3db..a4040d8 100644
--- a/cmd/dump-db.cc
+++ b/cmd/dump-db.cc
@@ -45,7 +45,7 @@
sqlite3_prepare_v2 (m_db,
"SELECT device_name, seq_no, action, filename, version, file_hash, file_seg_num, parent_device_name, parent_seq_no "
" FROM ActionLog "
- /*" ORDER BY filename,version"*/, -1, &stmt, 0);
+ " ORDER BY action_timestamp", -1, &stmt, 0);
cout.setf(std::ios::left, std::ios::adjustfield);
cout << ">> ACTION LOG <<" << endl;
diff --git a/gui/chronosharegui.cpp b/gui/chronosharegui.cpp
index f310594..d1c6898 100644
--- a/gui/chronosharegui.cpp
+++ b/gui/chronosharegui.cpp
@@ -93,7 +93,8 @@
// Alex: this **must** be here, otherwise m_dirPath will be uninitialized
m_watcher = new FsWatcher (m_dirPath,
bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
- bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1));
+ bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1),
+ m_dispatcher->GetFileState ());
}
ChronoShareGui::~ChronoShareGui()
diff --git a/gui/fs-watcher.cc b/gui/fs-watcher.cc
index 94c6b3f..7eff410 100644
--- a/gui/fs-watcher.cc
+++ b/gui/fs-watcher.cc
@@ -35,6 +35,7 @@
FsWatcher::FsWatcher (QString dirPath,
LocalFile_Change_Callback onChange, LocalFile_Change_Callback onDelete,
+ FileState *fileState,
QObject* parent)
: QObject(parent)
, m_watcher (new QFileSystemWatcher())
@@ -42,6 +43,7 @@
, m_dirPath (dirPath)
, m_onChange (onChange)
, m_onDelete (onDelete)
+ , m_fileState (fileState)
{
_LOG_DEBUG ("Monitor dir: " << m_dirPath.toStdString ());
// add main directory to monitor
@@ -54,8 +56,12 @@
m_scheduler->start ();
- Scheduler::scheduleOneTimeTask (m_scheduler, 0.1,
- bind (&FsWatcher::ScanDirectory_Notify_Execute, this, m_dirPath),
+ Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
+ bind (&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, m_dirPath),
+ "r-" + m_dirPath.toStdString ()); // only one task will be scheduled per directory
+
+ Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
+ bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, m_dirPath),
m_dirPath.toStdString ()); // only one task will be scheduled per directory
}
@@ -69,10 +75,23 @@
{
_LOG_DEBUG ("Triggered DirPath: " << dirPath.toStdString ());
- // m_executor.execute (bind (&FsWatcher::ScanDirectory_Notify_Execute, this, dirPath));
- Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
- bind (&FsWatcher::ScanDirectory_Notify_Execute, this, dirPath),
- dirPath.toStdString ()); // only one task will be scheduled per directory
+ filesystem::path absPathTriggeredDir (dirPath.toStdString ());
+ dirPath.remove (0, m_dirPath.size ());
+
+ filesystem::path triggeredDir (dirPath.toStdString ());
+ if (!filesystem::exists (filesystem::path (absPathTriggeredDir)))
+ {
+ Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
+ bind (&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, dirPath),
+ "r-" + dirPath.toStdString ()); // only one task will be scheduled per directory
+ }
+ else
+ {
+ // m_executor.execute (bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
+ Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
+ bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath),
+ dirPath.toStdString ()); // only one task will be scheduled per directory
+ }
}
void
@@ -103,13 +122,15 @@
Scheduler::scheduleOneTimeTask (m_scheduler, 0.5,
bind (m_onDelete, triggeredFile.relative_path ()),
- triggeredFile.relative_path ().string());
+ "r-" + triggeredFile.relative_path ().string());
}
}
void
-FsWatcher::ScanDirectory_Notify_Execute (QString dirPath)
+FsWatcher::ScanDirectory_NotifyUpdates_Execute (QString dirPath)
{
+ // _LOG_TRACE (" >> ScanDirectory_NotifyUpdates_Execute");
+
// exclude working only on last component, not the full path; iterating through all directories, even excluded from monitoring
QRegExp exclude ("^(\\.|\\.\\.|\\.chronoshare|.*~|.*\\.swp)$");
@@ -139,25 +160,6 @@
{
DidFileChanged (absFilePath);
}
- // // if this is a directory
- // if(fileInfo.isDir())
- // {
- // QStringList dirList = m_watcher->directories();
-
- // // if the directory is not already being watched
- // if (absFilePath.startsWith(m_dirPath) && !dirList.contains(absFilePath))
- // {
- // _LOG_DEBUG ("Add new dir to watchlist: " << absFilePath.toStdString ());
- // // add this directory to the watch list
- // m_watcher->addPath(absFilePath);
- // }
- // }
- // else
- // {
- // _LOG_DEBUG ("Found file: " << absFilePath.toStdString ());
- // // add this file to the file list
- // // currentState.insert(absFilePath, fileInfo.created().toMSecsSinceEpoch());
- // }
}
else
{
@@ -166,6 +168,31 @@
}
}
+
+void
+FsWatcher::ScanDirectory_NotifyRemovals_Execute (QString dirPath)
+{
+ _LOG_DEBUG ("Triggered DirPath: " << dirPath.toStdString ());
+
+ filesystem::path absPathTriggeredDir (dirPath.toStdString ());
+ dirPath.remove (0, m_dirPath.size ());
+
+ filesystem::path triggeredDir (dirPath.toStdString ());
+
+ FileItemsPtr files = m_fileState->LookupFilesInFolderRecursively (triggeredDir.generic_string ());
+ for (std::list<FileItem>::iterator file = files->begin (); file != files->end (); file ++)
+ {
+ filesystem::path testFile = filesystem::path (m_dirPath.toStdString ()) / file->filename ();
+ _LOG_DEBUG ("Check file for deletion [" << testFile.generic_string () << "]");
+
+ if (!filesystem::exists (testFile))
+ {
+ _LOG_DEBUG ("Notifying about removed file [" << file->filename () << "]");
+ m_onDelete (file->filename ());
+ }
+ }
+}
+
// std::vector<sEventInfo> FsWatcher::reconcileDirectory(QHash<QString, qint64> currentState, QString dirPath)
// {
// // list of files changed
diff --git a/gui/fs-watcher.h b/gui/fs-watcher.h
index 109e8da..b541382 100644
--- a/gui/fs-watcher.h
+++ b/gui/fs-watcher.h
@@ -27,6 +27,7 @@
#include <boost/filesystem.hpp>
#include "scheduler.h"
+#include "file-state.h"
class FsWatcher : public QObject
{
@@ -38,6 +39,7 @@
// constructor
FsWatcher (QString dirPath,
LocalFile_Change_Callback onChange, LocalFile_Change_Callback onDelete,
+ FileState *fileState,
QObject* parent = 0);
// destructor
@@ -59,7 +61,10 @@
// handle callback from the watcher
// scan directory and notify callback about any file changes
void
- ScanDirectory_Notify_Execute (QString dirPath);
+ ScanDirectory_NotifyUpdates_Execute (QString dirPath);
+
+ void
+ ScanDirectory_NotifyRemovals_Execute (QString dirPath);
// // reconcile directory, find changes
// std::vector<sEventInfo>
@@ -79,6 +84,8 @@
LocalFile_Change_Callback m_onChange;
LocalFile_Change_Callback m_onDelete;
+
+ FileState *m_fileState;
};
#endif // FILESYSTEMWATCHER_H
diff --git a/src/action-log.cc b/src/action-log.cc
index 32820b6..2bab7ca 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -88,6 +88,7 @@
CREATE TABLE FileState ( \n\
type INTEGER NOT NULL, /* 0 - newest, 1 - oldest */ \n\
filename TEXT NOT NULL, \n\
+ directory TEXT, \n\
device_name BLOB NOT NULL, \n\
seq_no INTEGER NOT NULL, \n\
file_hash BLOB NOT NULL, \n\
@@ -104,6 +105,10 @@
CREATE INDEX FileState_type_file_hash ON FileState (type, file_hash); \n\
";
+static void xTrace (void*, const char* q)
+{
+ _LOG_TRACE ("SQLITE: " << q);
+}
ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
SyncLogPtr syncLog,
@@ -127,6 +132,21 @@
BOOST_THROW_EXCEPTION (Error::Db ()
<< errmsg_info_str ("Cannot create function ``apply_action''"));
}
+
+
+ res = sqlite3_create_function (m_db, "directory_name", -1, SQLITE_ANY, 0,
+ ActionLog::directory_name_xFun,
+ 0, 0);
+ if (res != SQLITE_OK)
+ {
+ BOOST_THROW_EXCEPTION (Error::Db ()
+ << errmsg_info_str ("Cannot create function ``directory_name''"));
+ }
+
+ // "Upgrading" database
+ sqlite3_exec (m_db, "ALTER TABLE FileState ADD COLUMN directory TEXT", NULL, NULL, NULL);
+ sqlite3_exec (m_db, "CREATE INDEX FileState_directory ON FileState (directory)", NULL, NULL, NULL);
+ sqlite3_exec (m_db, "UPDATE FileState SET directory = directory_name(filename) WHERE directory IS NULL", NULL, NULL, NULL);
}
tuple<sqlite3_int64 /*version*/, Ccnx::CcnxCharbufPtr /*device name*/, sqlite3_int64 /*seq_no*/>
@@ -263,7 +283,7 @@
sqlite3_step (stmt);
- _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
@@ -314,14 +334,14 @@
sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, seq_no);
sqlite3_bind_int (stmt, 3, 1);
- sqlite3_bind_text (stmt, 4, filename.c_str (), filename.size (), SQLITE_TRANSIENT);
+ sqlite3_bind_text (stmt, 4, filename.c_str (), filename.size (), SQLITE_TRANSIENT); // file
+
sqlite3_bind_int64 (stmt, 5, version);
sqlite3_bind_int64 (stmt, 6, action_time);
sqlite3_bind_blob (stmt, 7, parent_device_name->buf (), parent_device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 8, parent_seq_no);
-
ActionItemPtr item = make_shared<ActionItem> ();
item->set_action (ActionItem::DELETE);
item->set_filename (filename);
@@ -342,7 +362,7 @@
sqlite3_step (stmt);
- _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
// cout << Ccnx::Name (parent_device_name) << endl;
@@ -417,7 +437,7 @@
{
_LOG_TRACE ("No action found for name: " << actionName);
}
- _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
return retval;
@@ -495,7 +515,7 @@
// if action needs to be applied to file state, the trigger will take care of it
- _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
@@ -590,7 +610,7 @@
"file_mtime=datetime(?, 'unixepoch'),"
"file_ctime=datetime(?, 'unixepoch'),"
"file_chmod=?, "
- "file_seg_num=? "
+ "file_seg_num=?, "
"WHERE type=0 AND filename=?", -1, &stmt, 0);
sqlite3_bind_blob (stmt, 1, device_name.buf (), device_name.length (), SQLITE_TRANSIENT);
@@ -605,7 +625,7 @@
sqlite3_step (stmt);
- _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_OK,
+ _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_ROW && sqlite3_errcode (the->m_db) != SQLITE_DONE,
sqlite3_errmsg (the->m_db));
sqlite3_finalize (stmt);
@@ -615,9 +635,9 @@
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (the->m_db, "INSERT INTO FileState "
- "(type,filename,device_name,seq_no,file_hash,file_atime,file_mtime,file_ctime,file_chmod,file_seg_num) "
+ "(type,filename,device_name,seq_no,file_hash,file_atime,file_mtime,file_ctime,file_chmod,file_seg_num,directory) "
"VALUES (0, ?, ?, ?, ?, "
- "datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?, ?)", -1, &stmt, 0);
+ "datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?, ?, directory_name(?))", -1, &stmt, 0);
sqlite3_bind_text (stmt, 1, filename.c_str (), -1, SQLITE_TRANSIENT);
sqlite3_bind_blob (stmt, 2, device_name.buf (), device_name.length (), SQLITE_TRANSIENT);
@@ -628,9 +648,10 @@
sqlite3_bind_int64 (stmt, 7, ctime);
sqlite3_bind_int (stmt, 8, mode);
sqlite3_bind_int (stmt, 9, seg_num);
+ sqlite3_bind_text (stmt, 10, filename.c_str (), -1, SQLITE_TRANSIENT);
sqlite3_step (stmt);
- _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_OK,
+ _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_DONE,
sqlite3_errmsg (the->m_db));
sqlite3_finalize (stmt);
}
@@ -711,3 +732,118 @@
return retval;
}
+
+
+FileItemsPtr
+ActionLog::LookupFilesInFolder (const std::string &folder)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db,
+ "SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num "
+ " FROM FileState "
+ " WHERE type = 0 AND directory = ?", -1, &stmt, 0);
+ sqlite3_bind_text (stmt, 1, folder.c_str (), folder.size (), SQLITE_STATIC);
+
+ FileItemsPtr retval = make_shared<FileItems> ();
+ while (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ FileItem file;
+ file.set_filename (reinterpret_cast<const char *> (sqlite3_column_text (stmt, 0)), sqlite3_column_bytes (stmt, 0));
+ file.set_device_name (sqlite3_column_blob (stmt, 1), sqlite3_column_bytes (stmt, 1));
+ file.set_seq_no (sqlite3_column_int64 (stmt, 2));
+ file.set_file_hash (sqlite3_column_blob (stmt, 3), sqlite3_column_bytes (stmt, 3));
+ file.set_mtime (sqlite3_column_int (stmt, 4));
+ file.set_mode (sqlite3_column_int (stmt, 5));
+ file.set_seg_num (sqlite3_column_int64 (stmt, 6));
+
+ retval->push_back (file);
+ }
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+
+ return retval;
+}
+
+FileItemsPtr
+ActionLog::LookupFilesInFolderRecursively (const std::string &folder)
+{
+ // sqlite3_trace(m_db, xTrace, NULL);
+
+ sqlite3_stmt *stmt;
+
+ if (folder != "")
+ {
+ sqlite3_prepare_v2 (m_db,
+ "SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num "
+ " FROM FileState "
+ " WHERE type = 0 AND (directory = ? OR directory LIKE ?)", -1, &stmt, 0);
+ sqlite3_bind_text (stmt, 1, folder.c_str (), folder.size (), SQLITE_STATIC);
+
+ ostringstream escapedFolder;
+ for (string::const_iterator ch = folder.begin (); ch != folder.end (); ch ++)
+ {
+ if (*ch == '%')
+ escapedFolder << "\\%";
+ else
+ escapedFolder << *ch;
+ }
+ escapedFolder << "/" << "%";
+ string escapedFolderStr = escapedFolder.str ();
+ sqlite3_bind_text (stmt, 2, escapedFolderStr.c_str (), escapedFolderStr.size (), SQLITE_STATIC);
+ }
+ else
+ {
+ sqlite3_prepare_v2 (m_db,
+ "SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num "
+ " FROM FileState "
+ " WHERE type = 0", -1, &stmt, 0);
+ }
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ FileItemsPtr retval = make_shared<FileItems> ();
+ while (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ FileItem file;
+ file.set_filename (reinterpret_cast<const char *> (sqlite3_column_text (stmt, 0)), sqlite3_column_bytes (stmt, 0));
+ file.set_device_name (sqlite3_column_blob (stmt, 1), sqlite3_column_bytes (stmt, 1));
+ file.set_seq_no (sqlite3_column_int64 (stmt, 2));
+ file.set_file_hash (sqlite3_column_blob (stmt, 3), sqlite3_column_bytes (stmt, 3));
+ file.set_mtime (sqlite3_column_int (stmt, 4));
+ file.set_mode (sqlite3_column_int (stmt, 5));
+ file.set_seg_num (sqlite3_column_int64 (stmt, 6));
+
+ retval->push_back (file);
+ }
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+
+ return retval;
+}
+
+void
+ActionLog::ActionLog::directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+ if (argc != 1)
+ {
+ sqlite3_result_error (context, "``directory_name'' expects 1 text argument", -1);
+ sqlite3_result_null (context);
+ return;
+ }
+
+ if (sqlite3_value_bytes (argv[0]) == 0)
+ {
+ sqlite3_result_null (context);
+ return;
+ }
+
+ filesystem::path filePath (string (reinterpret_cast<const char*> (sqlite3_value_text (argv[0])), sqlite3_value_bytes (argv[0])));
+ string dirPath = filePath.parent_path ().generic_string ();
+
+ sqlite3_result_text (context, dirPath.c_str (), dirPath.size (), SQLITE_TRANSIENT);
+}
+
diff --git a/src/action-log.h b/src/action-log.h
index 9833b92..f28a398 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -23,6 +23,7 @@
#define ACTION_LOG_H
#include "db-helper.h"
+#include "file-state.h"
#include "sync-log.h"
#include "action-item.pb.h"
#include "file-item.pb.h"
@@ -35,11 +36,8 @@
typedef boost::shared_ptr<ActionLog> ActionLogPtr;
typedef boost::shared_ptr<ActionItem> ActionItemPtr;
-typedef std::list<FileItem> FileItems;
-typedef boost::shared_ptr<FileItem> FileItemPtr;
-typedef boost::shared_ptr<FileItems> FileItemsPtr;
-
class ActionLog : public DbHelper
+ , public FileState
{
public:
typedef boost::function<void (std::string /*filename*/, Ccnx::Name /*device_name*/, sqlite3_int64 /*seq_no*/,
@@ -53,6 +51,8 @@
const std::string &sharedFolder,
OnFileAddedOrChangedCallback onFileAddedOrChanged, OnFileRemovedCallback onFileRemoved);
+ virtual ~ActionLog () { }
+
//////////////////////////
// Local operations //
//////////////////////////
@@ -103,12 +103,18 @@
///////////////////////////
// File state operations //
///////////////////////////
- FileItemPtr
+ virtual FileItemPtr
LookupFile (const std::string &filename);
- FileItemsPtr
+ virtual FileItemsPtr
LookupFilesForHash (const Hash &hash);
+ virtual FileItemsPtr
+ LookupFilesInFolder (const std::string &folder);
+
+ virtual FileItemsPtr
+ LookupFilesInFolderRecursively (const std::string &folder);
+
public:
// for test purposes
sqlite3_int64
@@ -121,6 +127,9 @@
static void
apply_action_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
+ static void
+ directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
+
private:
SyncLogPtr m_syncLog;
diff --git a/src/dispatcher.cc b/src/dispatcher.cc
index 03de6a9..cc677b6 100644
--- a/src/dispatcher.cc
+++ b/src/dispatcher.cc
@@ -118,6 +118,12 @@
m_server->deregisterPrefix(oldLocalPrefix);
}
+void
+Dispatcher::Restore_LocalFile (FileItemPtr file)
+{
+ m_executor.execute (bind (&Dispatcher::Restore_LocalFile_Execute, this, file));
+}
+
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -387,3 +393,29 @@
permissions (filePath, static_cast<filesystem::perms> (file->mode ()));
}
}
+
+void
+Dispatcher::Restore_LocalFile_Execute (FileItemPtr file)
+{
+ _LOG_DEBUG ("Got request to restore local file [" << file->filename () << "]");
+ // the rest will gracefully fail if object-db is missing or incomplete
+
+ boost::filesystem::path filePath = m_rootDir / file->filename ();
+ Name deviceName (file->device_name ().c_str (), file->device_name ().size ());
+ Hash hash (file->file_hash ().c_str (), file->file_hash ().size ());
+
+ if (filesystem::exists (filePath) &&
+ filesystem::last_write_time (filePath) == file->mtime () &&
+ filesystem::status (filePath).permissions () == static_cast<filesystem::perms> (file->mode ()) &&
+ *Hash::FromFileContent (filePath) == hash)
+ {
+ _LOG_DEBUG ("Asking to assemble a file, but file already exists on a filesystem");
+ return;
+ }
+
+ m_objectManager.objectsToLocalFile (deviceName, hash, filePath);
+
+ last_write_time (filePath, file->mtime ());
+ permissions (filePath, static_cast<filesystem::perms> (file->mode ()));
+
+}
diff --git a/src/dispatcher.h b/src/dispatcher.h
index b2b1e5c..100123f 100644
--- a/src/dispatcher.h
+++ b/src/dispatcher.h
@@ -64,10 +64,22 @@
void
Did_LocalFile_Delete (const boost::filesystem::path &relativeFilepath);
+ /**
+ * @brief Invoked when FileState is detected to have a file which does not exist on a file system
+ */
+ void
+ Restore_LocalFile (FileItemPtr file);
+
+ void
+ Restore_LocalFile_Execute (FileItemPtr file);
+
// for test
HashPtr
SyncRoot() { return m_core->root(); }
+ FileState *
+ GetFileState () { return m_actionLog.get (); }
+
private:
void
Did_LocalFile_AddOrModify_Execute (boost::filesystem::path relativeFilepath); // cannot be const & for Execute event!!! otherwise there will be segfault
diff --git a/src/file-state.cc b/src/file-state.cc
new file mode 100644
index 0000000..343d6a5
--- /dev/null
+++ b/src/file-state.cc
@@ -0,0 +1,22 @@
+/* -*- 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>
+ */
+
+#include "file-state.h"
diff --git a/src/file-state.h b/src/file-state.h
new file mode 100644
index 0000000..c7396f4
--- /dev/null
+++ b/src/file-state.h
@@ -0,0 +1,59 @@
+/* -*- 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 FILE_STATE_H
+#define FILE_STATE_H
+
+#include "file-item.pb.h"
+#include "hash-helper.h"
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/exception/all.hpp>
+
+#include <list>
+
+typedef std::list<FileItem> FileItems;
+typedef boost::shared_ptr<FileItem> FileItemPtr;
+typedef boost::shared_ptr<FileItems> FileItemsPtr;
+
+
+class FileState
+{
+public:
+ virtual FileItemPtr
+ LookupFile (const std::string &filename) = 0;
+
+ virtual FileItemsPtr
+ LookupFilesForHash (const Hash &hash) = 0;
+
+ virtual FileItemsPtr
+ LookupFilesInFolder (const std::string &folder) = 0;
+
+ virtual FileItemsPtr
+ LookupFilesInFolderRecursively (const std::string &folder) = 0;
+};
+
+namespace Error {
+struct FileState : virtual boost::exception, virtual std::exception { };
+}
+
+
+#endif // ACTION_LOG_H
diff --git a/src/sync-log.cc b/src/sync-log.cc
index 4298a9e..06eb1e7 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -32,7 +32,7 @@
using namespace std;
using namespace Ccnx;
-void xTrace (void*, const char* q)
+static void xTrace (void*, const char* q)
{
cout << q << endl;
}