blob: 6e637cfa3e9890ac9528cdff7fffb30e892548c2 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -08003 * Copyright (c) 2013-2017, Regents of the University of California.
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080019 */
20
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "fs-watcher.hpp"
Lijing Wange0dd63e2015-05-31 16:25:16 -070022#include "core/logging.hpp"
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080023
24#include <QDirIterator>
25#include <QRegExp>
26
Lijing Wange0dd63e2015-05-31 16:25:16 -070027namespace ndn {
28namespace chronoshare {
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080029
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080030_LOG_INIT(FsWatcher);
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080031
Lijing Wange0dd63e2015-05-31 16:25:16 -070032namespace fs = boost::filesystem;
33
34FsWatcher::FsWatcher(boost::asio::io_service& io, QString dirPath, LocalFile_Change_Callback onChange,
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080035 LocalFile_Change_Callback onDelete, QObject* parent)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080036 : QObject(parent)
Lijing Wange0dd63e2015-05-31 16:25:16 -070037 , m_watcher(new QFileSystemWatcher(this))
38 , m_scheduler(io)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080039 , m_dirPath(dirPath)
40 , m_onChange(onChange)
41 , m_onDelete(onDelete)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080042{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080043 _LOG_DEBUG("Monitor dir: " << m_dirPath.toStdString());
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080044 // add main directory to monitor
Alexander Afanasyev69e13172013-01-25 17:16:27 -080045
Zhenkai Zhud1756272013-02-01 17:02:18 -080046 initFileStateDb();
47
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080048 m_watcher->addPath(m_dirPath);
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080049
Lijing Wange0dd63e2015-05-31 16:25:16 -070050 // register signals(callback functions)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080051 connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(DidDirectoryChanged(QString)));
52 connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(DidFileChanged(QString)));
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080053
Lijing Wange0dd63e2015-05-31 16:25:16 -070054 rescheduleEvent("rescan", m_dirPath.toStdString(), time::seconds(0),
55 bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, m_dirPath));
Alexander Afanasyev583449a2013-01-28 17:04:06 -080056
Lijing Wange0dd63e2015-05-31 16:25:16 -070057 rescheduleEvent("rescan-r", m_dirPath.toStdString(), time::seconds(0),
58 bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, m_dirPath));
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080059}
60
61FsWatcher::~FsWatcher()
62{
Zhenkai Zhud1756272013-02-01 17:02:18 -080063 sqlite3_close(m_db);
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080064}
65
66void
Lijing Wange0dd63e2015-05-31 16:25:16 -070067FsWatcher::rescheduleEvent(const std::string& eventType, const std::string& path,
68 const time::milliseconds& period, const Scheduler::Event& callback)
69{
70 util::scheduler::ScopedEventId event(m_scheduler);
71 event = m_scheduler.scheduleEvent(period, callback);
72
73 // only one task per directory/file
74 std::string key = eventType + ":" + path;
75 m_events.erase(key);
76 m_events.insert(std::make_pair(key, std::move(event)));
77}
78
79void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080080FsWatcher::DidDirectoryChanged(QString dirPath)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080081{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080082 _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString());
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080083
Lijing Wange0dd63e2015-05-31 16:25:16 -070084 fs::path absPathTriggeredDir(dirPath.toStdString());
85 if (!fs::exists(fs::path(absPathTriggeredDir))) {
86 rescheduleEvent("r-", dirPath.toStdString(), time::milliseconds(500),
87 bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, dirPath));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080088 }
89 else {
Lijing Wange0dd63e2015-05-31 16:25:16 -070090 rescheduleEvent("", dirPath.toStdString(), time::milliseconds(500),
91 bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
Alexander Afanasyevc80207d2013-01-29 20:07:39 -080092
Lijing Wange0dd63e2015-05-31 16:25:16 -070093 // rescan updated folder for updates
94 rescheduleEvent("rescan", dirPath.toStdString(), time::seconds(300),
95 bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
Alexander Afanasyev7a647002013-01-30 11:54:52 -080096
Lijing Wange0dd63e2015-05-31 16:25:16 -070097 // rescan whole folder for deletions
98 rescheduleEvent("rescan-r", m_dirPath.toStdString(), time::seconds(300),
99 bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, m_dirPath));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800100 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800101}
102
103void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800104FsWatcher::DidFileChanged(QString filePath)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800105{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800106 if (!filePath.startsWith(m_dirPath)) {
107 _LOG_ERROR(
108 "Got notification about a file not from the monitored directory: " << filePath.toStdString());
109 return;
110 }
Alexander Afanasyeve70a2d82013-02-19 22:49:10 -0800111 QString absFilePath = filePath;
112
Lijing Wange0dd63e2015-05-31 16:25:16 -0700113 fs::path absPathTriggeredFile(filePath.toStdString());
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800114 filePath.remove(0, m_dirPath.size());
Alexander Afanasyev69e13172013-01-25 17:16:27 -0800115
Lijing Wange0dd63e2015-05-31 16:25:16 -0700116 fs::path triggeredFile(filePath.toStdString());
117 if (fs::exists(fs::path(absPathTriggeredFile))) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800118 _LOG_DEBUG("Triggered UPDATE of file: " << triggeredFile.relative_path().generic_string());
Lijing Wange0dd63e2015-05-31 16:25:16 -0700119 // m_onChange(triggeredFile.relative_path());
Alexander Afanasyev583449a2013-01-28 17:04:06 -0800120
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800121 m_watcher->removePath(absFilePath);
122 m_watcher->addPath(absFilePath);
Alexander Afanasyeve70a2d82013-02-19 22:49:10 -0800123
Lijing Wange0dd63e2015-05-31 16:25:16 -0700124 rescheduleEvent("", triggeredFile.relative_path().string(), time::milliseconds(500),
125 bind(m_onChange, triggeredFile.relative_path()));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800126 }
127 else {
128 _LOG_DEBUG("Triggered DELETE of file: " << triggeredFile.relative_path().generic_string());
Lijing Wange0dd63e2015-05-31 16:25:16 -0700129 // m_onDelete(triggeredFile.relative_path());
Yingdi Yu57f667b2013-07-11 10:37:59 -0700130
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800131 m_watcher->removePath(absFilePath);
Alexander Afanasyev583449a2013-01-28 17:04:06 -0800132
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800133 deleteFile(triggeredFile.relative_path());
Lijing Wange0dd63e2015-05-31 16:25:16 -0700134
135 rescheduleEvent("r", triggeredFile.relative_path().string(), time::milliseconds(500),
136 bind(m_onDelete, triggeredFile.relative_path()));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800137 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800138}
139
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800140void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800141FsWatcher::ScanDirectory_NotifyUpdates_Execute(QString dirPath)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800142{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800143 _LOG_TRACE(" >> ScanDirectory_NotifyUpdates_Execute");
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800144
Lijing Wange0dd63e2015-05-31 16:25:16 -0700145 // exclude working only on last component, not the full path; iterating through all directories,
146 // even excluded from monitoring
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800147 QRegExp exclude("^(\\.|\\.\\.|\\.chronoshare|.*~|.*\\.swp)$");
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800148
Lijing Wange0dd63e2015-05-31 16:25:16 -0700149 QDirIterator dirIterator(dirPath, QDir::Dirs | QDir::Files | /*QDir::Hidden |*/ QDir::NoSymLinks |
150 QDir::NoDotAndDotDot,
151 QDirIterator::Subdirectories); // directory iterator(recursive)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800152
153 // iterate through directory recursively
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800154 while (dirIterator.hasNext()) {
155 dirIterator.next();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800156
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800157 // Get FileInfo
158 QFileInfo fileInfo = dirIterator.fileInfo();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800159
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800160 QString name = fileInfo.fileName();
161 _LOG_DEBUG("+++ Scanning: " << name.toStdString());
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800162
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800163 if (!exclude.exactMatch(name)) {
164 _LOG_DEBUG("Not excluded file/dir: " << fileInfo.absoluteFilePath().toStdString());
165 QString absFilePath = fileInfo.absoluteFilePath();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800166
Lijing Wange0dd63e2015-05-31 16:25:16 -0700167 // _LOG_DEBUG("Attempt to add path to watcher: " << absFilePath.toStdString());
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800168 m_watcher->removePath(absFilePath);
169 m_watcher->addPath(absFilePath);
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800170
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800171 if (fileInfo.isFile()) {
172 QString relFile = absFilePath;
173 relFile.remove(0, m_dirPath.size());
Lijing Wange0dd63e2015-05-31 16:25:16 -0700174 fs::path aFile(relFile.toStdString());
Alexander Afanasyevf695aed2013-01-30 13:28:42 -0800175
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800176 if (
Lijing Wange0dd63e2015-05-31 16:25:16 -0700177 //!m_fileState->LookupFile(aFile.relative_path().generic_string())
178 ///* file does not exist there, but exists locally: added */)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800179 !fileExists(aFile.relative_path()) /*file does not exist in db, but exists in fs: add */) {
180 addFile(aFile.relative_path());
181 DidFileChanged(absFilePath);
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800182 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800183 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800184 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800185 else {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700186 // _LOG_DEBUG("Excluded file/dir: " << fileInfo.filePath().toStdString());
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800187 }
188 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800189}
190
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800191
192void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800193FsWatcher::ScanDirectory_NotifyRemovals_Execute(QString dirPath)
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800194{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800195 _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString());
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800196
Lijing Wange0dd63e2015-05-31 16:25:16 -0700197 fs::path absPathTriggeredDir(dirPath.toStdString());
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800198 dirPath.remove(0, m_dirPath.size());
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800199
Lijing Wange0dd63e2015-05-31 16:25:16 -0700200 fs::path triggeredDir(dirPath.toStdString());
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800201
Zhenkai Zhud1756272013-02-01 17:02:18 -0800202 /*
Lijing Wange0dd63e2015-05-31 16:25:16 -0700203 FileItemsPtr files = m_fileState->LookupFilesInFolderRecursively(triggeredDir.relative_path().generic_string());
204 for (std::list<FileItem>::iterator file = files->begin(); file != files->end(); file ++)
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800205 {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700206 fs::path testFile = fs::path(m_dirPath.toStdString()) / file->filename();
207 _LOG_DEBUG("Check file for deletion [" << testFile.generic_string() << "]");
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800208
Lijing Wange0dd63e2015-05-31 16:25:16 -0700209 if (!fs::exists(testFile))
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800210 {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700211 if (removeIncomplete || file->is_complete())
Alexander Afanasyev7a647002013-01-30 11:54:52 -0800212 {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700213 _LOG_DEBUG("Notifying about removed file [" << file->filename() << "]");
214 m_onDelete(file->filename());
Alexander Afanasyev7a647002013-01-30 11:54:52 -0800215 }
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800216 }
217 }
Zhenkai Zhud1756272013-02-01 17:02:18 -0800218 */
219
Lijing Wange0dd63e2015-05-31 16:25:16 -0700220 std::vector<std::string> files;
Alexander Afanasyev89024ac2013-02-14 09:38:10 -0800221 getFilesInDir(triggeredDir.relative_path(), files);
Lijing Wange0dd63e2015-05-31 16:25:16 -0700222 for (std::vector<std::string>::iterator file = files.begin(); file != files.end(); file++) {
223 fs::path targetFile = fs::path(m_dirPath.toStdString()) / *file;
224 if (!fs::exists(targetFile)) {
Alexander Afanasyev89024ac2013-02-14 09:38:10 -0800225 deleteFile(*file);
226 m_onDelete(*file);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800227 }
228 }
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800229}
230
Lijing Wange0dd63e2015-05-31 16:25:16 -0700231const std::string INIT_DATABASE = "\
232CREATE TABLE IF NOT EXISTS \n\
233 Files( \n\
234 filename TEXT NOT NULL, \n\
235 PRIMARY KEY(filename) \n\
236); \n\
237CREATE INDEX IF NOT EXISTS filename_index ON Files(filename); \n\
Zhenkai Zhud1756272013-02-01 17:02:18 -0800238";
239
240void
241FsWatcher::initFileStateDb()
242{
Lijing Wange0dd63e2015-05-31 16:25:16 -0700243 fs::path dbFolder = fs::path(m_dirPath.toStdString()) / ".chronoshare" / "fs_watcher";
244 fs::create_directories(dbFolder);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800245
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800246 int res = sqlite3_open((dbFolder / "filestate.db").string().c_str(), &m_db);
247 if (res != SQLITE_OK) {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700248 BOOST_THROW_EXCEPTION(Error("Cannot open database: " + (dbFolder / "filestate.db").string()));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800249 }
250
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800251 char* errmsg = 0;
Zhenkai Zhud1756272013-02-01 17:02:18 -0800252 res = sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, &errmsg);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800253 if (res != SQLITE_OK && errmsg != 0) {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700254 // _LOG_TRACE("Init \"error\": " << errmsg);
255 std::cout << "FS-Watcher DB error: " << errmsg << std::endl;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800256 sqlite3_free(errmsg);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800257 }
258}
259
260bool
Lijing Wange0dd63e2015-05-31 16:25:16 -0700261FsWatcher::fileExists(const fs::path& filename)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800262{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800263 sqlite3_stmt* stmt;
Zhenkai Zhud1756272013-02-01 17:02:18 -0800264 sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename = ?;", -1, &stmt, 0);
265 sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC);
266 bool retval = false;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800267 if (sqlite3_step(stmt) == SQLITE_ROW) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800268 retval = true;
269 }
270 sqlite3_finalize(stmt);
271
272 return retval;
273}
274
275void
Lijing Wange0dd63e2015-05-31 16:25:16 -0700276FsWatcher::addFile(const fs::path& filename)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800277{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800278 sqlite3_stmt* stmt;
Lijing Wange0dd63e2015-05-31 16:25:16 -0700279 sqlite3_prepare_v2(m_db, "INSERT OR IGNORE INTO Files(filename) VALUES(?);", -1, &stmt, 0);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800280 sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC);
281 sqlite3_step(stmt);
282 sqlite3_finalize(stmt);
283}
284
285void
Lijing Wange0dd63e2015-05-31 16:25:16 -0700286FsWatcher::deleteFile(const fs::path& filename)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800287{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800288 sqlite3_stmt* stmt;
Zhenkai Zhud1756272013-02-01 17:02:18 -0800289 sqlite3_prepare_v2(m_db, "DELETE FROM Files WHERE filename = ?;", -1, &stmt, 0);
290 sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC);
291 sqlite3_step(stmt);
292 sqlite3_finalize(stmt);
293}
294
295void
Lijing Wange0dd63e2015-05-31 16:25:16 -0700296FsWatcher::getFilesInDir(const fs::path& dir, std::vector<std::string>& files)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800297{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800298 sqlite3_stmt* stmt;
Zhenkai Zhud1756272013-02-01 17:02:18 -0800299 sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename LIKE ?;", -1, &stmt, 0);
300
Lijing Wange0dd63e2015-05-31 16:25:16 -0700301 std::string dirStr = dir.string();
302 std::ostringstream escapedDir;
303 for (std::string::const_iterator ch = dirStr.begin(); ch != dirStr.end(); ch++) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800304 if (*ch == '%')
305 escapedDir << "\\%";
306 else
307 escapedDir << *ch;
308 }
309 escapedDir << "/"
310 << "%";
Lijing Wange0dd63e2015-05-31 16:25:16 -0700311 std::string escapedDirStr = escapedDir.str();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800312 sqlite3_bind_text(stmt, 1, escapedDirStr.c_str(), escapedDirStr.size(), SQLITE_STATIC);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800313
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800314 while (sqlite3_step(stmt) == SQLITE_ROW) {
Lijing Wange0dd63e2015-05-31 16:25:16 -0700315 std::string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
316 sqlite3_column_bytes(stmt, 0));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800317 files.push_back(filename);
318 }
319
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800320 sqlite3_finalize(stmt);
Zhenkai Zhud1756272013-02-01 17:02:18 -0800321}
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800322
Lijing Wange0dd63e2015-05-31 16:25:16 -0700323} // namespace chronoshare
324} // namespace ndn
325
326#ifdef WAF
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800327#include "fs-watcher.moc"
Lijing Wange0dd63e2015-05-31 16:25:16 -0700328// #include "fs-watcher.cpp.moc"
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800329#endif