Skip to content

Commit

Permalink
FolderWatcher: Use csync exclude code owncloud#3805
Browse files Browse the repository at this point in the history
Introduce a global ExcludedFiles instance to avoid loading the global
exclude lists several times.

One could still add per-folder exclude lists by checking these after
the global ones.
  • Loading branch information
ckamm committed Oct 2, 2015
1 parent 95fc792 commit 7d18866
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 163 deletions.
9 changes: 8 additions & 1 deletion src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "accountmanager.h"
#include "creds/abstractcredentials.h"
#include "updater/ocupdater.h"
#include "excludedfiles.h"

#include "config.h"

Expand Down Expand Up @@ -135,6 +136,13 @@ Application::Application(int &argc, char **argv) :
setupLogging();
setupTranslations();

// Setup global excludes
ConfigFile cfg;
ExcludedFiles& excludes = ExcludedFiles::instance();
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::SystemScope) );
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::UserScope) );
excludes.reloadExcludes();

_folderManager.reset(new FolderMan);

connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
Expand All @@ -145,7 +153,6 @@ Application::Application(int &argc, char **argv) :

setQuitOnLastWindowClosed(false);

ConfigFile cfg;
_theme->setSystrayUseMonoIcons(cfg.monoIcons());
connect (_theme, SIGNAL(systrayUseMonoIconsChanged(bool)), SLOT(slotUseMonoIconsChanged(bool)));

Expand Down
19 changes: 18 additions & 1 deletion src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include "syncrunfilelog.h"
#include "theme.h"
#include "filesystem.h"

#include "excludedfiles.h"

#include "creds/abstractcredentials.h"

Expand Down Expand Up @@ -707,6 +707,23 @@ void Folder::removeFromSettings() const
settings->remove(_definition.alias);
}

bool Folder::isFileExcluded(const QString& fullPath) const
{
QString myFullPath = fullPath;
if (myFullPath.endsWith(QLatin1Char('/'))) {
myFullPath.chop(1);
}

if (!myFullPath.startsWith(path())) {
// Mark paths we're not responsible for as excluded...
return true;
}

QString relativePath = myFullPath.mid(path().size());
auto excl = ExcludedFiles::instance().isExcluded(myFullPath, relativePath, _definition.ignoreHiddenFiles);
return excl != CSYNC_NOT_EXCLUDED;
}

void Folder::watcherSlot(QString fn)
{
// FIXME: On OS X we could not do this "if" since on OS X the file watcher ignores events for ourselves
Expand Down
5 changes: 5 additions & 0 deletions src/gui/folder.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ class Folder : public QObject
/// Removes the folder from the account's settings.
void removeFromSettings() const;

/**
* Returns whether a file inside this folder should be excluded.
*/
bool isFileExcluded(const QString& fullPath) const;

signals:
void syncStateChange();
void syncStarted();
Expand Down
12 changes: 0 additions & 12 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ FolderMan::FolderMan(QObject *parent) :
_instance = this;

_socketApi = new SocketApi(this);
_socketApi->slotReadExcludes();

ConfigFile cfg;
int polltime = cfg.remotePollInterval();
Expand Down Expand Up @@ -149,10 +148,6 @@ void FolderMan::registerFolderMonitor( Folder *folder )

if( !_folderWatchers.contains(folder->alias() ) ) {
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
ConfigFile cfg;
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::SystemScope) );
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::UserScope) );
fw->setIgnoreHidden( folder->ignoreHiddenFiles() );

// Connect the pathChanged signal, which comes with the changed path,
// to the signal mapper which maps to the folder alias. The changed path
Expand Down Expand Up @@ -696,13 +691,6 @@ void FolderMan::slotStartScheduledFolderSync()
_currentSyncFolder = f;

f->startSync( QStringList() );

// reread the excludes of the socket api
// FIXME: the excludes need rework.
if( _socketApi ) {
_socketApi->slotClearExcludesList();
_socketApi->slotReadExcludes();
}
}
}

Expand Down
84 changes: 11 additions & 73 deletions src/gui/folderwatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
#include "folderwatcher_linux.h"
#endif

#include "excludedfiles.h"
#include "folder.h"

namespace OCC {

FolderWatcher::FolderWatcher(const QString &root, QObject *parent)
: QObject(parent),
_ignoreHidden(true)
FolderWatcher::FolderWatcher(const QString &root, Folder* folder)
: QObject(folder),
_folder(folder)
{
_d.reset(new FolderWatcherPrivate(this, root));

Expand All @@ -47,81 +49,17 @@ FolderWatcher::FolderWatcher(const QString &root, QObject *parent)
FolderWatcher::~FolderWatcher()
{ }

void FolderWatcher::setIgnoreHidden(bool ignore)
{
_ignoreHidden = ignore;
}

bool FolderWatcher::ignoreHidden()
{
return _ignoreHidden;
}

void FolderWatcher::addIgnoreListFile( const QString& file )
{
if( file.isEmpty() ) return;

QFile infile( file );
if (!infile.open(QIODevice::ReadOnly | QIODevice::Text))
return;

while (!infile.atEnd()) {
QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed();
if( !(line.startsWith( QLatin1Char('#') ) || line.isEmpty()) ) {
_ignores.append(line);
}
}
}

QStringList FolderWatcher::ignores() const
{
return _ignores;
}

bool FolderWatcher::pathIsIgnored( const QString& path )
{
if( path.isEmpty() ) return true;
if( !_folder ) return false;

// if events caused by changes to hidden files should be ignored, a QFileInfo
// object will tell us if the file is hidden
if( _ignoreHidden ) {
QFileInfo fInfo(path);
if( fInfo.isHidden() ) {
qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
return true;
}
}

// TODO: Best use csync_excluded_no_ctx() here somehow!
foreach (QString pattern, _ignores) {
// The leading ] is a tag and not part of the pattern.
if (pattern.startsWith(']')) {
pattern.remove(0, 1);
}

if(pattern.endsWith('/')) {
// directory only pattern. But since path components are
// checked later, we cut off the trailing dir.
pattern.chop(1);
}

QRegExp regexp(pattern);
regexp.setPatternSyntax(QRegExp::Wildcard);

// if the pattern contains / it needs to match the entire path
if (pattern.contains('/') && regexp.exactMatch(path)) {
qDebug() << "* Discarded by ignore pattern: " << path;
return true;
}

QStringList components = path.split('/');
foreach (const QString& comp, components) {
if(regexp.exactMatch(comp)) {
qDebug() << "* Discarded by component ignore pattern " << comp;
return true;
}
}
#ifndef OWNCLOUD_TEST
if (_folder->isFileExcluded(path)) {
qDebug() << "* Ignoring file" << path;
return true;
}
#endif
return false;
}

Expand Down
20 changes: 3 additions & 17 deletions src/gui/folderwatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class QTimer;
namespace OCC {

class FolderWatcherPrivate;
class Folder;

/**
* @brief Montiors a directory recursively for changes
Expand All @@ -53,19 +54,9 @@ class FolderWatcher : public QObject
/**
* @param root Path of the root of the folder
*/
FolderWatcher(const QString &root, QObject *parent = 0L);
FolderWatcher(const QString &root, Folder* folder = 0L);
virtual ~FolderWatcher();

/**
* Set a file name to load a file with ignore patterns.
*
* Valid entries do not start with a hash sign (#)
* and may contain wildcards
*/
void addIgnoreListFile( const QString& );

QStringList ignores() const;

/**
* Not all backends are recursive by default.
* Those need to be notified when a directory is added or removed while the watcher is disabled.
Expand All @@ -77,10 +68,6 @@ class FolderWatcher : public QObject
/* Check if the path is ignored. */
bool pathIsIgnored( const QString& path );

/* set if the folderwatcher ignores events of hidden files */
void setIgnoreHidden(bool ignore);
bool ignoreHidden();

signals:
/** Emitted when one of the watched directories or one
* of the contained files is changed. */
Expand All @@ -99,10 +86,9 @@ protected slots:

private:
QScopedPointer<FolderWatcherPrivate> _d;
QStringList _ignores;
QTime _timer;
QSet<QString> _lastPaths;
bool _ignoreHidden;
Folder* _folder;

friend class FolderWatcherPrivate;
};
Expand Down
3 changes: 3 additions & 0 deletions src/gui/ignorelisteditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ignorelisteditor.h"
#include "folderman.h"
#include "ui_ignorelisteditor.h"
#include "excludedfiles.h"

#include <QFile>
#include <QDir>
Expand Down Expand Up @@ -126,6 +127,8 @@ void IgnoreListEditor::slotUpdateLocalIgnoreList()
folder->journalDb()->forceRemoteDiscoveryNextSync();
folderMan->slotScheduleSync(folder);
}

ExcludedFiles::instance().reloadExcludes();
}

void IgnoreListEditor::slotAddPattern()
Expand Down
55 changes: 4 additions & 51 deletions src/gui/socketapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,12 @@
// The second number should be changed when there are new features.
#define MIRALL_SOCKET_API_VERSION "1.0"

extern "C" {

enum csync_exclude_type_e {
CSYNC_NOT_EXCLUDED = 0,
CSYNC_FILE_SILENTLY_EXCLUDED,
CSYNC_FILE_EXCLUDE_AND_REMOVE,
CSYNC_FILE_EXCLUDE_LIST,
CSYNC_FILE_EXCLUDE_INVALID_CHAR,
CSYNC_FILE_EXCLUDE_LONG_FILENAME,
CSYNC_FILE_EXCLUDE_HIDDEN
};
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;

CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype);
int csync_exclude_load(const char *fname, c_strlist_t **list);
}

namespace OCC {

#define DEBUG qDebug() << "SocketApi: "

SocketApi::SocketApi(QObject* parent)
: QObject(parent)
, _excludes(0)
{
QString socketPath;

Expand Down Expand Up @@ -141,29 +123,6 @@ SocketApi::~SocketApi()
// All remaining sockets will be destroyed with _localServer, their parent
Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
_listeners.clear();
slotClearExcludesList();
c_strlist_destroy(_excludes);
}

void SocketApi::slotClearExcludesList()
{
c_strlist_clear(_excludes);
}

void SocketApi::slotReadExcludes()
{
ConfigFile cfgFile;
slotClearExcludesList();
QString excludeList = cfgFile.excludeFile( ConfigFile::SystemScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added system ignore list to socketapi:" << excludeList.toUtf8();
csync_exclude_load(excludeList.toUtf8(), &_excludes);
}
excludeList = cfgFile.excludeFile( ConfigFile::UserScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added user defined ignore list to csync:" << excludeList.toUtf8();
csync_exclude_load(excludeList.toUtf8(), &_excludes);
}
}

void SocketApi::slotNewConnection()
Expand Down Expand Up @@ -268,7 +227,7 @@ void SocketApi::slotUpdateFolderView(Folder *f)
f->syncResult().status() == SyncResult::SetupError ) {

broadcastMessage(QLatin1String("STATUS"), f->path() ,
this->fileStatus(f, "", _excludes).toSocketAPIString());
this->fileStatus(f, "").toSocketAPIString());

broadcastMessage(QLatin1String("UPDATE_VIEW"), f->path() );
} else {
Expand Down Expand Up @@ -387,7 +346,7 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice*
statusString = QLatin1String("NOP");
} else {
const QString file = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1);
SyncFileStatus fileStatus = this->fileStatus(syncFolder, file, _excludes);
SyncFileStatus fileStatus = this->fileStatus(syncFolder, file);

statusString = fileStatus.toSocketAPIString();
}
Expand Down Expand Up @@ -541,7 +500,7 @@ SyncJournalFileRecord SocketApi::dbFileRecord_capi( Folder *folder, QString file
/**
* Get status about a single file.
*/
SyncFileStatus SocketApi::fileStatus(Folder *folder, const QString& systemFileName, c_strlist_t *excludes )
SyncFileStatus SocketApi::fileStatus(Folder *folder, const QString& systemFileName)
{
QString file = folder->path();
QString fileName = systemFileName.normalized(QString::NormalizationForm_C);
Expand Down Expand Up @@ -581,13 +540,7 @@ SyncFileStatus SocketApi::fileStatus(Folder *folder, const QString& systemFileNa
}

// Is it excluded?
CSYNC_EXCLUDE_TYPE excl = csync_excluded_no_ctx(excludes, fileName.toUtf8(), type);
if( folder->ignoreHiddenFiles()
&& (fi.isHidden()
|| fi.fileName().startsWith(QLatin1Char('.'))) ) {
excl = CSYNC_FILE_EXCLUDE_HIDDEN;
}
if( excl != CSYNC_NOT_EXCLUDED ) {
if( folder->isFileExcluded(file) ) {
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
}

Expand Down
Loading

0 comments on commit 7d18866

Please sign in to comment.