Project

General

Profile

Patch #163 ยป linuxdirwatch.diff

dyblast dyblast, 03/29/2011 08:28 PM

View differences:

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;
};
}
    (1-1/1)