Patch #163 ยป linuxdirwatch.diff
| application/Common/Version.h | ||
|---|---|---|
| #define VERSION_TAG "Beta10" | ||
| // These two values are automatically updated during the release building process. See the script 'Application/Tools/update_version.sh' | ||
| #define BUILD_TIME "2011-03-28_13-03" | ||
| #define GIT_VERSION "57073952baf03b969debc1c36411eb755a03e2ca" | ||
| #define BUILD_TIME "2011-03-28_21-03" | ||
| #define GIT_VERSION "b4ed2536331d34ae92de94e82de03f0c5cb25c29" | ||
| #endif | ||
| application/Core/FileManager/FileManager.pro | ||
|---|---|---|
| # -------------------------------------------------
 | ||
| # Project created by QtCreator 2009-10-04T18:54:43
 | ||
| # -------------------------------------------------
 | ||
| QT -= gui
 | ||
| QT += network
 | ||
| TARGET = FileManager
 | ||
| TEMPLATE = lib
 | ||
|  | ||
| include(../../Common/common.pri)
 | ||
| include(../../Libs/protobuf.pri)
 | ||
|  | ||
| CONFIG += staticlib link_prl create_prl
 | ||
|  | ||
| INCLUDEPATH += . ../..
 | ||
|  | ||
| LIBS += -L../../Common/LogManager/output/$$FOLDER -lLogManager
 | ||
| POST_TARGETDEPS += ../../Common/LogManager/output/$$FOLDER/libLogManager.a
 | ||
|  | ||
| LIBS += -L../../Common/output/$$FOLDER -lCommon
 | ||
| POST_TARGETDEPS += ../../Common/output/$$FOLDER/libCommon.a
 | ||
|  | ||
| DEFINES += FILEMANAGER_LIBRARY
 | ||
| SOURCES += priv/Builder.cpp \
 | ||
|     priv/FileManager.cpp \
 | ||
|     priv/FileUpdater/FileUpdater.cpp \
 | ||
|     priv/FileUpdater/DirWatcherWin.cpp \
 | ||
|     priv/FileUpdater/DirWatcher.cpp \
 | ||
|     priv/Cache/Entry.cpp \
 | ||
|     priv/Cache/File.cpp \
 | ||
|     priv/Cache/Directory.cpp \
 | ||
|     priv/Cache/SharedDirectory.cpp \
 | ||
|     priv/ChunkIndex/Chunks.cpp \
 | ||
|     ../../Protos/core_protocol.pb.cc \
 | ||
|     ../../Protos/common.pb.cc \
 | ||
|     priv/Cache/Chunk.cpp \
 | ||
|     priv/Cache/DataReader.cpp \
 | ||
|     priv/Cache/DataWriter.cpp \
 | ||
|     priv/Cache/Cache.cpp \
 | ||
|     ../../Protos/files_cache.pb.cc \
 | ||
|     priv/FileUpdater/WaitCondition.cpp \
 | ||
|     priv/FileUpdater/WaitConditionWin.cpp \
 | ||
|     priv/FileUpdater/WaitConditionLinux.cpp \
 | ||
|     priv/GetHashesResult.cpp \
 | ||
|     priv/Log.cpp \
 | ||
|     priv/Global.cpp
 | ||
| HEADERS += IGetHashesResult.h \
 | ||
|     IFileManager.h \
 | ||
|     IChunk.h \
 | ||
|     Builder.h \
 | ||
|     priv/Log.h \
 | ||
|     priv/FileManager.h \
 | ||
|     priv/FileUpdater/FileUpdater.h \
 | ||
|     priv/FileUpdater/DirWatcherWin.h \
 | ||
|     priv/FileUpdater/DirWatcher.h \
 | ||
|     priv/Cache/Entry.h \
 | ||
|     priv/Cache/File.h \
 | ||
|     priv/Cache/Directory.h \
 | ||
|     priv/Cache/SharedDirectory.h \
 | ||
|     priv/ChunkIndex/Chunks.h \
 | ||
|     priv/WordIndex/WordIndex.h \
 | ||
|     priv/WordIndex/Node.h \
 | ||
|     ../../Protos/core_protocol.pb.h \
 | ||
|     ../../Protos/common.pb.h \
 | ||
|     IDataReader.h \
 | ||
|     IDataWriter.h \
 | ||
|     priv/Cache/Chunk.h \
 | ||
|     priv/Cache/DataReader.h \
 | ||
|     priv/Cache/DataWriter.h \
 | ||
|     priv/Cache/Cache.h \
 | ||
|     priv/Exceptions.h \
 | ||
|     Exceptions.h \
 | ||
|     ../../Protos/files_cache.pb.h \
 | ||
|     priv/FileUpdater/WaitCondition.h \
 | ||
|     priv/FileUpdater/WaitConditionWin.h \
 | ||
|     priv/FileUpdater/WaitConditionLinux.h \
 | ||
|     priv/Constants.h \
 | ||
|     priv/GetHashesResult.h \
 | ||
|     priv/Global.h
 | ||
| OTHER_FILES +=
 | ||
| # ------------------------------------------------- | ||
| # Project created by QtCreator 2009-10-04T18:54:43 | ||
| # ------------------------------------------------- | ||
| QT -= gui | ||
| QT += network | ||
| TARGET = FileManager | ||
| TEMPLATE = lib | ||
| include(../../Common/common.pri) | ||
| include(../../Libs/protobuf.pri) | ||
| CONFIG += staticlib link_prl create_prl | ||
| INCLUDEPATH += . ../.. | ||
| LIBS += -L../../Common/LogManager/output/$$FOLDER -lLogManager | ||
| POST_TARGETDEPS += ../../Common/LogManager/output/$$FOLDER/libLogManager.a | ||
| LIBS += -L../../Common/output/$$FOLDER -lCommon | ||
| POST_TARGETDEPS += ../../Common/output/$$FOLDER/libCommon.a | ||
| DEFINES += FILEMANAGER_LIBRARY | ||
| SOURCES += priv/Builder.cpp \ | ||
|     priv/FileManager.cpp \ | ||
|     priv/FileUpdater/FileUpdater.cpp \ | ||
|     priv/FileUpdater/DirWatcherWin.cpp \ | ||
|     priv/FileUpdater/DirWatcherLinux.cpp \ | ||
|     priv/FileUpdater/DirWatcher.cpp \ | ||
|     priv/Cache/Entry.cpp \ | ||
|     priv/Cache/File.cpp \ | ||
|     priv/Cache/Directory.cpp \ | ||
|     priv/Cache/SharedDirectory.cpp \ | ||
|     priv/ChunkIndex/Chunks.cpp \ | ||
|     ../../Protos/core_protocol.pb.cc \ | ||
|     ../../Protos/common.pb.cc \ | ||
|     priv/Cache/Chunk.cpp \ | ||
|     priv/Cache/DataReader.cpp \ | ||
|     priv/Cache/DataWriter.cpp \ | ||
|     priv/Cache/Cache.cpp \ | ||
|     ../../Protos/files_cache.pb.cc \ | ||
|     priv/FileUpdater/WaitCondition.cpp \ | ||
|     priv/FileUpdater/WaitConditionWin.cpp \ | ||
|     priv/FileUpdater/WaitConditionLinux.cpp \ | ||
|     priv/GetHashesResult.cpp \ | ||
|     priv/Log.cpp \ | ||
|     priv/Global.cpp | ||
| HEADERS += IGetHashesResult.h \ | ||
|     IFileManager.h \ | ||
|     IChunk.h \ | ||
|     Builder.h \ | ||
|     priv/Log.h \ | ||
|     priv/FileManager.h \ | ||
|     priv/FileUpdater/FileUpdater.h \ | ||
|     priv/FileUpdater/DirWatcherWin.h \ | ||
|     priv/FileUpdater/DirWatcherLinux.h \ | ||
|     priv/FileUpdater/DirWatcher.h \ | ||
|     priv/Cache/Entry.h \ | ||
|     priv/Cache/File.h \ | ||
|     priv/Cache/Directory.h \ | ||
|     priv/Cache/SharedDirectory.h \ | ||
|     priv/ChunkIndex/Chunks.h \ | ||
|     priv/WordIndex/WordIndex.h \ | ||
|     priv/WordIndex/Node.h \ | ||
|     ../../Protos/core_protocol.pb.h \ | ||
|     ../../Protos/common.pb.h \ | ||
|     IDataReader.h \ | ||
|     IDataWriter.h \ | ||
|     priv/Cache/Chunk.h \ | ||
|     priv/Cache/DataReader.h \ | ||
|     priv/Cache/DataWriter.h \ | ||
|     priv/Cache/Cache.h \ | ||
|     priv/Exceptions.h \ | ||
|     Exceptions.h \ | ||
|     ../../Protos/files_cache.pb.h \ | ||
|     priv/FileUpdater/WaitCondition.h \ | ||
|     priv/FileUpdater/WaitConditionWin.h \ | ||
|     priv/FileUpdater/WaitConditionLinux.h \ | ||
|     priv/Constants.h \ | ||
|     priv/GetHashesResult.h \ | ||
|     priv/Global.h | ||
| OTHER_FILES += | ||
| application/Core/FileManager/priv/FileUpdater/DirWatcher.cpp | ||
|---|---|---|
| #if defined(Q_OS_WIN32) | ||
|    #include <priv/FileUpdater/DirWatcherWin.h> | ||
| #elif defined(Q_OS_LINUX) | ||
|    #include <priv/FileUpdater/DirWatcherLinux.h> | ||
| #endif | ||
| DirWatcher* DirWatcher::getNewWatcher() | ||
| ... | ... | |
| #if defined(Q_OS_WIN32) | ||
|    return new DirWatcherWin(); | ||
| #else | ||
|    L_WARN("Cannot create a watcher for the current platform, no implementation."); | ||
|    return 0; | ||
|    return new DirWatcherLinux(); | ||
| #endif | ||
| } | ||
| application/Core/FileManager/priv/FileUpdater/DirWatcherLinux.cpp | ||
|---|---|---|
| /** | ||
|   * D-LAN - A decentralized LAN file sharing software. | ||
|   * Copyright (C) 2010-2011 Greg Burri <greg.burri@gmail.com> | ||
|   * | ||
|   * This program 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. | ||
|   * | ||
|   * 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, see <http://www.gnu.org/licenses/>. | ||
|   */ | ||
| #include <QtCore/QDebug> | ||
| #include <QMutexLocker> | ||
| #if defined(Q_OS_LINUX) | ||
| #include <priv/FileUpdater/DirWatcherLinux.h> | ||
| using namespace FM; | ||
| #include <priv/Exceptions.h> | ||
| #include <priv/FileUpdater/WaitConditionLinux.h> | ||
| /** | ||
|   * @class FM::DirWatcherLinux | ||
|   * | ||
|   * Implementation of 'DirWatcher' for the linux platform. | ||
|   */ | ||
| DirWatcherLinux::DirWatcherLinux() : | ||
|     mutex(QMutex::Recursive) | ||
| { | ||
|     this->inotify_fd = inotify_init(); | ||
|     fcntl(this->inotify_fd, F_SETFL, O_NONBLOCK); | ||
| } | ||
| DirWatcherLinux::~DirWatcherLinux() | ||
| { | ||
|     QMutexLocker locker(&this->mutex); | ||
|     close(this->inotify_fd); | ||
|     this->dirs.clear(); | ||
| } | ||
| /** | ||
|   * @exception DirNotFoundException | ||
|   */ | ||
| bool DirWatcherLinux::addDir(const QString& path) | ||
| { | ||
|     QMutexLocker locker(&this->mutex); | ||
|     if(this->dirs.contains(path)) | ||
|     { | ||
|         L_WARN("Try to add an already watched directory: " + path); | ||
|         return false; | ||
|     } | ||
|     L_USER("Add path: " + path); | ||
|     int wd = inotify_add_watch(this->inotify_fd, path.toUtf8(), IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY ); | ||
|     this->dirs.insert(path, wd); | ||
|     return true; | ||
| } | ||
| void DirWatcherLinux::rmDir(const QString& path) | ||
| { | ||
|     QMutexLocker locker(&this->mutex); | ||
|     QMap<QString, int>::iterator it = this->dirs.find(path); | ||
|     if(it != this->dirs.end()) | ||
|     { | ||
|         L_USER("Remove path: " + path); | ||
|         inotify_rm_watch(this->inotify_fd, it.value()); | ||
|         this->dirs.erase(it); | ||
|     } | ||
|     else | ||
|     { | ||
|         L_WARN("Try to remove an unwatched directory: " + path); | ||
|     } | ||
| } | ||
| int DirWatcherLinux::nbWatchedDir() | ||
| { | ||
|     QMutexLocker locker(&this->mutex); | ||
|     return this->dirs.size(); | ||
| } | ||
| const QList<WatcherEvent> DirWatcherLinux::waitEvent(QList<WaitCondition*> ws) | ||
| { | ||
|     return this->waitEvent(-1, ws); | ||
| } | ||
| const QList<WatcherEvent> DirWatcherLinux::waitEvent(int timeout, QList<WaitCondition*> ws) | ||
| { | ||
|     QMutexLocker locker(&this->mutex); | ||
|     fd_set fds; | ||
|     int ret; | ||
|     int size; | ||
|     struct inotify_event notify_events[16]; | ||
|     FD_ZERO(&fds); | ||
|     FD_SET(this->inotify_fd, &fds); | ||
|     for(QList<WaitCondition*>::iterator it = ws.begin(); it != ws.end(); it ++) | ||
|     { | ||
|         WaitCondition* wc = reinterpret_cast<WaitCondition*>(*it); | ||
|         FD_SET((int)wc->getHandle(), &fds); | ||
|     } | ||
|     locker.unlock(); | ||
|     if(timeout != -1) | ||
|     { | ||
|         struct timeval tv; | ||
|         tv.tv_usec = (timeout % 1000) * 1000; | ||
|         tv.tv_sec = timeout / 1000; | ||
|         ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv) ; | ||
|     }else{ | ||
|         ret = select(FD_SETSIZE, &fds, NULL, NULL, 0) ; | ||
|     } | ||
|     locker.relock(); | ||
|     if (ret > 0) { | ||
|         if(FD_ISSET(this->inotify_fd, &fds)) | ||
|         { | ||
|             QList<WatcherEvent> events; | ||
|             QMap<int, QString> cookies; | ||
|             do | ||
|             { | ||
|                 size = read(this->inotify_fd, notify_events, sizeof(notify_events)); | ||
|                 if (size > 0) { | ||
|                     size /= sizeof(struct inotify_event); | ||
|                     for(int i = 0; i < size; i++) | ||
|                     { | ||
|                         QString path = this->dirs.key(notify_events[i].wd); | ||
|                         if(!path.isEmpty()) | ||
|                         { | ||
|                             QString fullpath = path + QString::fromUtf8(notify_events[i].name); | ||
|                             switch(notify_events[i].mask) | ||
|                             { | ||
|                             case  IN_CREATE : | ||
|                                 events << WatcherEvent(WatcherEvent::NEW, fullpath); | ||
|                                 L_USER(QString("CREATE: %1").arg(fullpath)); | ||
|                                 break; | ||
|                             case IN_DELETE : | ||
|                                 events << WatcherEvent(WatcherEvent::DELETED, fullpath); | ||
|                                 L_USER(QString("DELETED: %1").arg(fullpath)); | ||
|                                 break; | ||
|                             case IN_MOVED_FROM : | ||
|                                 cookies.insert(notify_events[i].cookie, fullpath); | ||
|                                 break; | ||
|                             case IN_MOVED_TO : | ||
|                                 if(cookies.contains(notify_events[i].cookie)) | ||
|                                 { | ||
|                                     QString old = cookies.take(notify_events[i].cookie); | ||
|                                     L_USER(QString("MOVE %1 -> %2").arg(old).arg(fullpath)); | ||
|                                     events << WatcherEvent(WatcherEvent::MOVE, old, fullpath); | ||
|                                 } | ||
|                                 else | ||
|                                 { | ||
|                                     events << WatcherEvent(WatcherEvent::NEW, fullpath); | ||
|                                     //TRICK: why only "new" file are not used? | ||
|                                     events << WatcherEvent(WatcherEvent::CONTENT_CHANGED, fullpath); | ||
|                                     L_USER(QString("CREATE: %1").arg(fullpath)); | ||
|                                 } | ||
|                                 break; | ||
|                             case IN_MODIFY: | ||
|                                 events << WatcherEvent(WatcherEvent::CONTENT_CHANGED, fullpath); | ||
|                                 L_USER(QString("MODIFIED: %1").arg(fullpath)); | ||
|                                 break; | ||
|                             } | ||
|                         } | ||
|                     } | ||
|                 } | ||
|             }while(size >0); | ||
|             for(QMap<int, QString>::iterator it = cookies.begin(); it != cookies.end(); ++it) | ||
|             { | ||
|                 QString fullpath = it.value(); | ||
|                 events << WatcherEvent(WatcherEvent::DELETED, fullpath); | ||
|                 L_USER(QString("DELETED: %1").arg(fullpath)); | ||
|             } | ||
|             return events; | ||
|         } | ||
|         else | ||
|         { | ||
|             return QList<WatcherEvent>(); | ||
|         } | ||
|     } | ||
|     else if(ret == 0) | ||
|     { | ||
|         QList<WatcherEvent> events; | ||
|         events.append(WatcherEvent(WatcherEvent::TIMEOUT)); | ||
|         return events; | ||
|     } | ||
|     else | ||
|     { | ||
|         L_ERRO(QString("select(..) failed, error code : %1").arg(errno)); | ||
|     } | ||
|     QList<WatcherEvent> events; | ||
|     events << WatcherEvent(WatcherEvent::UNKNOWN); | ||
|     return QList<WatcherEvent>(); | ||
| } | ||
| #endif | ||
| application/Core/FileManager/priv/FileUpdater/DirWatcherLinux.h | ||
|---|---|---|
| /** | ||
|   * D-LAN - A decentralized LAN file sharing software. | ||
|   * Copyright (C) 2010-2011 Greg Burri <greg.burri@gmail.com> | ||
|   * | ||
|   * This program 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. | ||
|   * | ||
|   * 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, see <http://www.gnu.org/licenses/>. | ||
|   */ | ||
| #include <QtCore/QtCore> // Only for the Q_OS_* defines. | ||
| #if !defined(FILEMANAGER_DIRWATCHERLINUX_H) and defined(Q_OS_LINUX) | ||
| #define FILEMANAGER_DIRWATCHERLINUX_H | ||
| #include <QMutex> | ||
| #include <priv/FileUpdater/DirWatcher.h> | ||
| #include <priv/Log.h> | ||
| #include <sys/inotify.h> | ||
| #include <errno.h> | ||
| namespace FM | ||
| { | ||
|    static const int NOTIFY_BUFFER_SIZE = 2048; | ||
|    static const int MAX_WAIT_CONDITION = 4; | ||
|    class DirWatcherLinux : public DirWatcher | ||
|    { | ||
|    public: | ||
|       DirWatcherLinux(); | ||
|       ~DirWatcherLinux(); | ||
|       bool addDir(const QString& path); | ||
|       void rmDir(const QString& path); | ||
|       int nbWatchedDir(); | ||
|       const QList<WatcherEvent> waitEvent(QList<WaitCondition*> ws = QList<WaitCondition*>()); | ||
|       const QList<WatcherEvent> waitEvent(int timeout, QList<WaitCondition*> ws = QList<WaitCondition*>()); | ||
|    private: | ||
|       QMap<QString, int> dirs; ///< The watched dirs. | ||
|       int inotify_fd; | ||
|       QMutex mutex; | ||
|    }; | ||
| } | ||
| #endif | ||
| application/Core/FileManager/priv/FileUpdater/WaitConditionLinux.cpp | ||
|---|---|---|
|   * You should have received a copy of the GNU General Public License | ||
|   * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||
|   */ | ||
|  | ||
| #include <QtCore/QDebug> | ||
| #if defined(Q_OS_LINUX) | ||
| ... | ... | |
| using namespace FM; | ||
| WaitConditionLinux::WaitConditionLinux() : | ||
|    released(false) | ||
|     released(false) | ||
| { | ||
|     this->e_fd = eventfd(0, 0); | ||
|     fcntl(this->e_fd, F_SETFL, O_NONBLOCK); | ||
| } | ||
| WaitConditionLinux::~WaitConditionLinux() | ||
| { | ||
|     close(this->e_fd); | ||
| } | ||
| void WaitConditionLinux::release() | ||
| { | ||
|    this->mutex.lock(); | ||
|    this->released = true; | ||
|    this->waitCondition.wakeOne(); | ||
|    this->mutex.unlock();       | ||
| {     | ||
|     char buffer[8]; | ||
|     int ret; | ||
|     memset(buffer, 1, 8); | ||
|     ret = write(this->e_fd, buffer, 8); | ||
| } | ||
| bool WaitConditionLinux::wait(int timeout) | ||
| { | ||
|    bool timeouted = false; | ||
|     fd_set rfds; | ||
|     char buffer[8]; | ||
|     int ret; | ||
|     int timeouted; | ||
|     FD_ZERO(&rfds); | ||
|     FD_SET(this->e_fd, &rfds); | ||
|    this->mutex.lock(); | ||
|    if (!this->released) | ||
|       timeouted = !this->waitCondition.wait(&this->mutex, timeout == -1 ? ULONG_MAX : timeout); | ||
|     if(timeout != -1) | ||
|     { | ||
|         struct timeval tv; | ||
|         tv.tv_usec = (timeout % 1000) * 1000; | ||
|         tv.tv_sec = timeout / 1000; | ||
|         timeouted = select(this->e_fd + 1, &rfds, NULL, NULL, &tv); | ||
|     }else{ | ||
|         timeouted = select(this->e_fd + 1, &rfds, NULL, NULL, NULL); | ||
|     } | ||
|    this->released = false; | ||
|    this->mutex.unlock(); | ||
|    return timeouted; | ||
|     ret = read(this->e_fd, buffer, 8); | ||
|     return timeouted == 0; | ||
| } | ||
| void* WaitConditionLinux::getHandle() | ||
| { | ||
|    return 0; | ||
|     return (void * )this->e_fd; | ||
| } | ||
| #endif | ||
| application/Core/FileManager/priv/FileUpdater/WaitConditionLinux.h | ||
|---|---|---|
| #if !defined(FILEMANAGER_WAITCONDITIONLINUX_H) and defined(Q_OS_LINUX) | ||
| #define FILEMANAGER_WAITCONDITIONLINUX_H | ||
| #include <QMutex> | ||
| #include <QWaitCondition> | ||
| #include <sys/eventfd.h> | ||
| #include <sys/types.h> | ||
| #include <unistd.h> | ||
| #include <fcntl.h> | ||
| #include <priv/FileUpdater/WaitCondition.h> | ||
| ... | ... | |
|    private: | ||
|       bool released; | ||
|       QMutex mutex; | ||
|       QWaitCondition waitCondition; | ||
|       int e_fd; | ||
|    }; | ||
| } | ||