Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 | /** |
Alexander Afanasyev | 1cf5c43 | 2017-01-13 23:22:15 -0800 | [diff] [blame] | 3 | * Copyright (c) 2013-2017, Regents of the University of California. |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 4 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 5 | * This file is part of ChronoShare, a decentralized file sharing application over NDN. |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 6 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 7 | * 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 Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 10 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 11 | * 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 Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 14 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 15 | * 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 Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 19 | */ |
| 20 | |
Alexander Afanasyev | f4cde4e | 2016-12-25 13:42:57 -0800 | [diff] [blame] | 21 | #include "fs-watcher.hpp" |
| 22 | #include "db-helper.hpp" |
| 23 | #include "logging.hpp" |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 24 | |
| 25 | #include <boost/bind.hpp> |
| 26 | |
| 27 | #include <QDirIterator> |
| 28 | #include <QRegExp> |
| 29 | |
| 30 | using namespace std; |
| 31 | using namespace boost; |
| 32 | |
Alexander Afanasyev | 1cf5c43 | 2017-01-13 23:22:15 -0800 | [diff] [blame] | 33 | _LOG_INIT(FsWatcher); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 34 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 35 | FsWatcher::FsWatcher(QString dirPath, LocalFile_Change_Callback onChange, |
| 36 | LocalFile_Change_Callback onDelete, QObject* parent) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 37 | : QObject(parent) |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 38 | , m_watcher(new QFileSystemWatcher()) |
| 39 | , m_scheduler(new Scheduler()) |
| 40 | , m_dirPath(dirPath) |
| 41 | , m_onChange(onChange) |
| 42 | , m_onDelete(onDelete) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 43 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 44 | _LOG_DEBUG("Monitor dir: " << m_dirPath.toStdString()); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 45 | // add main directory to monitor |
Alexander Afanasyev | 69e1317 | 2013-01-25 17:16:27 -0800 | [diff] [blame] | 46 | |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 47 | initFileStateDb(); |
| 48 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 49 | m_watcher->addPath(m_dirPath); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 50 | |
| 51 | // register signals (callback functions) |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 52 | connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(DidDirectoryChanged(QString))); |
| 53 | connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(DidFileChanged(QString))); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 54 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 55 | m_scheduler->start(); |
Alexander Afanasyev | 583449a | 2013-01-28 17:04:06 -0800 | [diff] [blame] | 56 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 57 | Scheduler::scheduleOneTimeTask(m_scheduler, 0, |
| 58 | bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, |
| 59 | m_dirPath), |
| 60 | "rescan-r-" + |
| 61 | m_dirPath.toStdString()); // only one task will be scheduled per directory |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 62 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 63 | Scheduler::scheduleOneTimeTask(m_scheduler, 0, bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, |
| 64 | this, m_dirPath), |
| 65 | "rescan-" + |
| 66 | m_dirPath.toStdString()); // only one task will be scheduled per directory |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | FsWatcher::~FsWatcher() |
| 70 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 71 | m_scheduler->shutdown(); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 72 | sqlite3_close(m_db); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 76 | FsWatcher::DidDirectoryChanged(QString dirPath) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 77 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 78 | _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString()); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 79 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 80 | filesystem::path absPathTriggeredDir(dirPath.toStdString()); |
| 81 | if (!filesystem::exists(filesystem::path(absPathTriggeredDir))) { |
| 82 | Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, |
| 83 | bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, |
| 84 | dirPath), |
| 85 | "r-" + dirPath.toStdString()); // only one task will be scheduled per directory |
| 86 | } |
| 87 | else { |
| 88 | // m_executor.execute (bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath)); |
| 89 | Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, |
| 90 | bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, |
| 91 | dirPath), |
| 92 | dirPath.toStdString()); // only one task will be scheduled per directory |
Alexander Afanasyev | c80207d | 2013-01-29 20:07:39 -0800 | [diff] [blame] | 93 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 94 | // m_executor.execute (bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath)); |
| 95 | Scheduler::scheduleOneTimeTask(m_scheduler, 300, |
| 96 | bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, |
| 97 | dirPath), |
| 98 | "rescan-" + |
| 99 | dirPath.toStdString()); // only one task will be scheduled per directory |
Alexander Afanasyev | 7a64700 | 2013-01-30 11:54:52 -0800 | [diff] [blame] | 100 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 101 | Scheduler::scheduleOneTimeTask(m_scheduler, 300, |
| 102 | bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, |
| 103 | m_dirPath), |
| 104 | "rescan-r-" + |
| 105 | m_dirPath.toStdString()); // only one task will be scheduled per directory |
| 106 | } |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 110 | FsWatcher::DidFileChanged(QString filePath) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 111 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 112 | if (!filePath.startsWith(m_dirPath)) { |
| 113 | _LOG_ERROR( |
| 114 | "Got notification about a file not from the monitored directory: " << filePath.toStdString()); |
| 115 | return; |
| 116 | } |
Alexander Afanasyev | e70a2d8 | 2013-02-19 22:49:10 -0800 | [diff] [blame] | 117 | QString absFilePath = filePath; |
| 118 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 119 | filesystem::path absPathTriggeredFile(filePath.toStdString()); |
| 120 | filePath.remove(0, m_dirPath.size()); |
Alexander Afanasyev | 69e1317 | 2013-01-25 17:16:27 -0800 | [diff] [blame] | 121 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 122 | filesystem::path triggeredFile(filePath.toStdString()); |
| 123 | if (filesystem::exists(filesystem::path(absPathTriggeredFile))) { |
| 124 | _LOG_DEBUG("Triggered UPDATE of file: " << triggeredFile.relative_path().generic_string()); |
| 125 | // m_onChange (triggeredFile.relative_path ()); |
Alexander Afanasyev | 583449a | 2013-01-28 17:04:06 -0800 | [diff] [blame] | 126 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 127 | m_watcher->removePath(absFilePath); |
| 128 | m_watcher->addPath(absFilePath); |
Alexander Afanasyev | e70a2d8 | 2013-02-19 22:49:10 -0800 | [diff] [blame] | 129 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 130 | Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, bind(m_onChange, triggeredFile.relative_path()), |
| 131 | triggeredFile.relative_path().string()); |
| 132 | } |
| 133 | else { |
| 134 | _LOG_DEBUG("Triggered DELETE of file: " << triggeredFile.relative_path().generic_string()); |
| 135 | // m_onDelete (triggeredFile.relative_path ()); |
Yingdi Yu | 57f667b | 2013-07-11 10:37:59 -0700 | [diff] [blame] | 136 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 137 | m_watcher->removePath(absFilePath); |
Alexander Afanasyev | 583449a | 2013-01-28 17:04:06 -0800 | [diff] [blame] | 138 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 139 | deleteFile(triggeredFile.relative_path()); |
| 140 | Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, bind(m_onDelete, triggeredFile.relative_path()), |
| 141 | "r-" + triggeredFile.relative_path().string()); |
| 142 | } |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 143 | } |
| 144 | |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 145 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 146 | FsWatcher::ScanDirectory_NotifyUpdates_Execute(QString dirPath) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 147 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 148 | _LOG_TRACE(" >> ScanDirectory_NotifyUpdates_Execute"); |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 149 | |
Alexander Afanasyev | 69e1317 | 2013-01-25 17:16:27 -0800 | [diff] [blame] | 150 | // exclude working only on last component, not the full path; iterating through all directories, even excluded from monitoring |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 151 | QRegExp exclude("^(\\.|\\.\\.|\\.chronoshare|.*~|.*\\.swp)$"); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 152 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 153 | QDirIterator dirIterator(dirPath, |
| 154 | QDir::Dirs | QDir::Files | /*QDir::Hidden |*/ QDir::NoSymLinks | |
| 155 | QDir::NoDotAndDotDot, |
| 156 | QDirIterator::Subdirectories); // directory iterator (recursive) |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 157 | |
| 158 | // iterate through directory recursively |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 159 | while (dirIterator.hasNext()) { |
| 160 | dirIterator.next(); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 161 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 162 | // Get FileInfo |
| 163 | QFileInfo fileInfo = dirIterator.fileInfo(); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 164 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 165 | QString name = fileInfo.fileName(); |
| 166 | _LOG_DEBUG("+++ Scanning: " << name.toStdString()); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 167 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 168 | if (!exclude.exactMatch(name)) { |
| 169 | _LOG_DEBUG("Not excluded file/dir: " << fileInfo.absoluteFilePath().toStdString()); |
| 170 | QString absFilePath = fileInfo.absoluteFilePath(); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 171 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 172 | // _LOG_DEBUG ("Attempt to add path to watcher: " << absFilePath.toStdString ()); |
| 173 | m_watcher->removePath(absFilePath); |
| 174 | m_watcher->addPath(absFilePath); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 175 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 176 | if (fileInfo.isFile()) { |
| 177 | QString relFile = absFilePath; |
| 178 | relFile.remove(0, m_dirPath.size()); |
| 179 | filesystem::path aFile(relFile.toStdString()); |
Alexander Afanasyev | f695aed | 2013-01-30 13:28:42 -0800 | [diff] [blame] | 180 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 181 | if ( |
| 182 | //!m_fileState->LookupFile (aFile.relative_path ().generic_string ()) /* file does not exist there, but exists locally: added */) |
| 183 | !fileExists(aFile.relative_path()) /*file does not exist in db, but exists in fs: add */) { |
| 184 | addFile(aFile.relative_path()); |
| 185 | DidFileChanged(absFilePath); |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 186 | } |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 187 | } |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 188 | } |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 189 | else { |
| 190 | // _LOG_DEBUG ("Excluded file/dir: " << fileInfo.filePath ().toStdString ()); |
| 191 | } |
| 192 | } |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 193 | } |
| 194 | |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 195 | |
| 196 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 197 | FsWatcher::ScanDirectory_NotifyRemovals_Execute(QString dirPath) |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 198 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 199 | _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString()); |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 200 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 201 | filesystem::path absPathTriggeredDir(dirPath.toStdString()); |
| 202 | dirPath.remove(0, m_dirPath.size()); |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 203 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 204 | filesystem::path triggeredDir(dirPath.toStdString()); |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 205 | |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 206 | /* |
Alexander Afanasyev | 506ff22 | 2013-01-29 18:12:55 -0800 | [diff] [blame] | 207 | FileItemsPtr files = m_fileState->LookupFilesInFolderRecursively (triggeredDir.relative_path ().generic_string ()); |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 208 | for (std::list<FileItem>::iterator file = files->begin (); file != files->end (); file ++) |
| 209 | { |
| 210 | filesystem::path testFile = filesystem::path (m_dirPath.toStdString ()) / file->filename (); |
| 211 | _LOG_DEBUG ("Check file for deletion [" << testFile.generic_string () << "]"); |
| 212 | |
| 213 | if (!filesystem::exists (testFile)) |
| 214 | { |
Alexander Afanasyev | 7a64700 | 2013-01-30 11:54:52 -0800 | [diff] [blame] | 215 | if (removeIncomplete || file->is_complete ()) |
| 216 | { |
| 217 | _LOG_DEBUG ("Notifying about removed file [" << file->filename () << "]"); |
| 218 | m_onDelete (file->filename ()); |
| 219 | } |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 220 | } |
| 221 | } |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 222 | */ |
| 223 | |
| 224 | vector<string> files; |
Alexander Afanasyev | 89024ac | 2013-02-14 09:38:10 -0800 | [diff] [blame] | 225 | getFilesInDir(triggeredDir.relative_path(), files); |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 226 | for (vector<string>::iterator file = files.begin(); file != files.end(); file++) { |
| 227 | filesystem::path targetFile = filesystem::path(m_dirPath.toStdString()) / *file; |
| 228 | if (!filesystem::exists(targetFile)) { |
Alexander Afanasyev | 89024ac | 2013-02-14 09:38:10 -0800 | [diff] [blame] | 229 | deleteFile(*file); |
| 230 | m_onDelete(*file); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 231 | } |
| 232 | } |
Alexander Afanasyev | 0a30a0c | 2013-01-29 17:25:42 -0800 | [diff] [blame] | 233 | } |
| 234 | |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 235 | const string INIT_DATABASE = "\ |
| 236 | CREATE TABLE IF NOT EXISTS \n\ |
| 237 | Files( \n\ |
| 238 | filename TEXT NOT NULL, \n\ |
| 239 | PRIMARY KEY (filename) \n\ |
| 240 | ); \n\ |
| 241 | CREATE INDEX filename_index ON Files (filename); \n\ |
| 242 | "; |
| 243 | |
| 244 | void |
| 245 | FsWatcher::initFileStateDb() |
| 246 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 247 | filesystem::path dbFolder = |
| 248 | filesystem::path(m_dirPath.toStdString()) / ".chronoshare" / "fs_watcher"; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 249 | filesystem::create_directories(dbFolder); |
| 250 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 251 | int res = sqlite3_open((dbFolder / "filestate.db").string().c_str(), &m_db); |
| 252 | if (res != SQLITE_OK) { |
| 253 | BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot open database: " + |
| 254 | (dbFolder / "filestate.db").string())); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 255 | } |
| 256 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 257 | char* errmsg = 0; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 258 | res = sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, &errmsg); |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 259 | if (res != SQLITE_OK && errmsg != 0) { |
| 260 | // _LOG_TRACE ("Init \"error\": " << errmsg); |
| 261 | cout << "FS-Watcher DB error: " << errmsg << endl; |
| 262 | sqlite3_free(errmsg); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 263 | } |
| 264 | } |
| 265 | |
| 266 | bool |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 267 | FsWatcher::fileExists(const filesystem::path& filename) |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 268 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 269 | sqlite3_stmt* stmt; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 270 | sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename = ?;", -1, &stmt, 0); |
| 271 | sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); |
| 272 | bool retval = false; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 273 | if (sqlite3_step(stmt) == SQLITE_ROW) { |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 274 | retval = true; |
| 275 | } |
| 276 | sqlite3_finalize(stmt); |
| 277 | |
| 278 | return retval; |
| 279 | } |
| 280 | |
| 281 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 282 | FsWatcher::addFile(const filesystem::path& filename) |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 283 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 284 | sqlite3_stmt* stmt; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 285 | sqlite3_prepare_v2(m_db, "INSERT OR IGNORE INTO Files (filename) VALUES (?);", -1, &stmt, 0); |
| 286 | sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); |
| 287 | sqlite3_step(stmt); |
| 288 | sqlite3_finalize(stmt); |
| 289 | } |
| 290 | |
| 291 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 292 | FsWatcher::deleteFile(const filesystem::path& filename) |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 293 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 294 | sqlite3_stmt* stmt; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 295 | sqlite3_prepare_v2(m_db, "DELETE FROM Files WHERE filename = ?;", -1, &stmt, 0); |
| 296 | sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); |
| 297 | sqlite3_step(stmt); |
| 298 | sqlite3_finalize(stmt); |
| 299 | } |
| 300 | |
| 301 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 302 | FsWatcher::getFilesInDir(const filesystem::path& dir, vector<string>& files) |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 303 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 304 | sqlite3_stmt* stmt; |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 305 | sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename LIKE ?;", -1, &stmt, 0); |
| 306 | |
| 307 | string dirStr = dir.string(); |
| 308 | ostringstream escapedDir; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 309 | for (string::const_iterator ch = dirStr.begin(); ch != dirStr.end(); ch++) { |
| 310 | if (*ch == '%') |
| 311 | escapedDir << "\\%"; |
| 312 | else |
| 313 | escapedDir << *ch; |
| 314 | } |
| 315 | escapedDir << "/" |
| 316 | << "%"; |
| 317 | string escapedDirStr = escapedDir.str(); |
| 318 | sqlite3_bind_text(stmt, 1, escapedDirStr.c_str(), escapedDirStr.size(), SQLITE_STATIC); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 319 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 320 | while (sqlite3_step(stmt) == SQLITE_ROW) { |
| 321 | string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), |
| 322 | sqlite3_column_bytes(stmt, 0)); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 323 | files.push_back(filename); |
| 324 | } |
| 325 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 326 | sqlite3_finalize(stmt); |
Zhenkai Zhu | d175627 | 2013-02-01 17:02:18 -0800 | [diff] [blame] | 327 | } |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 328 | |
| 329 | #if WAF |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 330 | #include "fs-watcher.cc.moc" |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame] | 331 | #include "fs-watcher.moc" |
Alexander Afanasyev | 9e5a470 | 2013-01-24 13:15:23 -0800 | [diff] [blame] | 332 | #endif |