Browse Source

- FEATURE: Folder scanning now works with CIFS and NFS mounted folders

adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
daef9ece75
  1. 1
      Changelog
  2. 44
      src/bittorrent.cpp
  3. 8
      src/bittorrent.h
  4. 182
      src/filesystemwatcher.h
  5. 3
      src/src.pro

1
Changelog

@ -16,6 +16,7 @@
- FEATURE: Dropped Qt 4.3 support (Qt >= 4.4 is required) - FEATURE: Dropped Qt 4.3 support (Qt >= 4.4 is required)
- FEATURE: Display more information regarding the torrent in its properties - FEATURE: Display more information regarding the torrent in its properties
- FEATURE: Various optimizations to save CPU and memory - FEATURE: Various optimizations to save CPU and memory
- FEATURE: Folder scanning now works with CIFS and NFS mounted folders
- COSMETIC: Merged download / upload lists - COSMETIC: Merged download / upload lists
- COSMETIC: Torrents can be filtered based on their status - COSMETIC: Torrents can be filtered based on their status
- COSMETIC: Torrent properties are now displayed in main window - COSMETIC: Torrent properties are now displayed in main window

44
src/bittorrent.cpp

@ -32,10 +32,9 @@
#include <QDateTime> #include <QDateTime>
#include <QString> #include <QString>
#include <QTimer> #include <QTimer>
#include <QFileSystemWatcher>
#include <QSettings> #include <QSettings>
#include <QMutex>
#include "filesystemwatcher.h"
#include "bittorrent.h" #include "bittorrent.h"
#include "misc.h" #include "misc.h"
#include "downloadThread.h" #include "downloadThread.h"
@ -89,9 +88,6 @@ bittorrent::bittorrent() : DHTEnabled(false), preAllocateAll(false), addInPause(
downloader = new downloadThread(this); downloader = new downloadThread(this);
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString))); connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
BigRatioTimer = 0;
filterParser = 0;
FSWatcher = 0;
qDebug("* BTSession constructed"); qDebug("* BTSession constructed");
} }
@ -114,7 +110,6 @@ bittorrent::~bittorrent() {
delete downloader; delete downloader;
if(FSWatcher) { if(FSWatcher) {
delete FSWatcher; delete FSWatcher;
delete FSMutex;
} }
// Delete BT session // Delete BT session
qDebug("Deleting session"); qDebug("Deleting session");
@ -969,25 +964,10 @@ bool bittorrent::isFilePreviewPossible(QString hash) const{
return false; return false;
} }
// Scan the first level of the directory for torrent files void bittorrent::addTorrentsFromScanFolder(QStringList &pathList) {
// and add them to download list QString dir_path = FSWatcher->directories().first();
void bittorrent::scanDirectory(QString scan_dir) { foreach(const QString &file, pathList) {
FSMutex->lock(); QString fullPath = dir_path+QDir::separator()+file;
qDebug("Scanning directory: %s", scan_dir.toLocal8Bit().data());
QDir dir(scan_dir);
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup");
// Check that scan dir is not BT_backup (silly but who knows...)
if(dir == torrentBackup) {
std::cerr << "Scan directory cannot be qBittorrent backup folder!" << std::endl;
return;
}
QStringList filters;
filters << "*.torrent";
QStringList files = dir.entryList(filters, QDir::Files, QDir::Unsorted);
foreach(const QString &file, files) {
QString fullPath = dir.path()+QDir::separator()+file;
QFile torrent(fullPath);
qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data());
try { try {
torrent_info t(fullPath.toLocal8Bit().data()); torrent_info t(fullPath.toLocal8Bit().data());
addTorrent(fullPath, true); addTorrent(fullPath, true);
@ -995,7 +975,6 @@ void bittorrent::scanDirectory(QString scan_dir) {
qDebug("Ignoring incomplete torrent file: %s", fullPath.toLocal8Bit().data()); qDebug("Ignoring incomplete torrent file: %s", fullPath.toLocal8Bit().data());
} }
} }
FSMutex->unlock();
} }
void bittorrent::setDefaultSavePath(QString savepath) { void bittorrent::setDefaultSavePath(QString savepath) {
@ -1050,21 +1029,17 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
newDir.mkpath(scan_dir); newDir.mkpath(scan_dir);
} }
if(FSWatcher == 0) { if(FSWatcher == 0) {
FSMutex = new QMutex(); // Set up folder watching
FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this); FSWatcher = new FileSystemWatcher(scan_dir, this);
connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString))); connect(FSWatcher, SIGNAL(torrentsAdded(QStringList&)), this, SLOT(addTorrentsFromScanFolder(QStringList&)));
// Initial scan
scanDirectory(scan_dir);
} else { } else {
QString old_scan_dir = ""; QString old_scan_dir = "";
if(!FSWatcher->directories().empty()) if(!FSWatcher->directories().empty())
old_scan_dir = FSWatcher->directories().first(); old_scan_dir = FSWatcher->directories().first();
if(old_scan_dir != scan_dir) { if(QDir(old_scan_dir) != QDir(scan_dir)) {
if(!old_scan_dir.isEmpty()) if(!old_scan_dir.isEmpty())
FSWatcher->removePath(old_scan_dir); FSWatcher->removePath(old_scan_dir);
FSWatcher->addPath(scan_dir); FSWatcher->addPath(scan_dir);
// Initial scan
scanDirectory(scan_dir);
} }
} }
} }
@ -1074,7 +1049,6 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
void bittorrent::disableDirectoryScanning() { void bittorrent::disableDirectoryScanning() {
if(FSWatcher) { if(FSWatcher) {
delete FSWatcher; delete FSWatcher;
delete FSMutex;
} }
} }

8
src/bittorrent.h

@ -44,8 +44,7 @@ using namespace libtorrent;
class downloadThread; class downloadThread;
class QTimer; class QTimer;
class QFileSystemWatcher; class FileSystemWatcher;
class QMutex;
class FilterParserThread; class FilterParserThread;
class bittorrent : public QObject { class bittorrent : public QObject {
@ -53,8 +52,7 @@ class bittorrent : public QObject {
private: private:
session *s; session *s;
QPointer<QFileSystemWatcher> FSWatcher; QPointer<FileSystemWatcher> FSWatcher;
QMutex* FSMutex;
QPointer<QTimer> timerAlerts; QPointer<QTimer> timerAlerts;
QPointer<QTimer> BigRatioTimer; QPointer<QTimer> BigRatioTimer;
bool DHTEnabled; bool DHTEnabled;
@ -172,7 +170,7 @@ class bittorrent : public QObject {
void downloadFromURLList(const QStringList& urls); void downloadFromURLList(const QStringList& urls);
protected slots: protected slots:
void scanDirectory(QString); void addTorrentsFromScanFolder(QStringList&);
void readAlerts(); void readAlerts();
void loadTrackerFile(QString hash); void loadTrackerFile(QString hash);
void deleteBigRatios(); void deleteBigRatios();

182
src/filesystemwatcher.h

@ -0,0 +1,182 @@
#ifndef FILESYSTEMWATCHER_H
#define FILESYSTEMWATCHER_H
#include <QFileSystemWatcher>
#ifndef Q_WS_WIN
#include <QTimer>
#include <QDir>
#include <QPointer>
#include <QStringList>
#include <QSet>
#include <iostream>
#include <errno.h>
#ifdef Q_WS_MAC
#include <sys/param.h>
#include <sys/mount.h>
#else
#include <sys/vfs.h>
#endif
#endif
#ifndef CIFS_MAGIC_NUMBER
#define CIFS_MAGIC_NUMBER 0xFF534D42
#endif
#ifndef NFS_SUPER_MAGIC
#define NFS_SUPER_MAGIC 0x6969
#endif
/*
* Subclassing QFileSystemWatcher in order to support Network File
* System watching (NFS, CIFS) on Linux and Mac OS.
*/
class FileSystemWatcher: public QFileSystemWatcher {
Q_OBJECT
#ifndef Q_WS_WIN
private:
QDir watched_folder;
QPointer<QTimer> watch_timer;
QStringList filters;
protected:
bool isNetworkFileSystem(QString path) {
QString file = path;
if(!file.endsWith(QDir::separator()))
file += QDir::separator();
file += ".";
struct statfs buf;
if(!statfs(file.toLocal8Bit().data(), &buf)) {
return (buf.f_type == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC);
} else {
std::cerr << "Error: statfs() call failed for " << file.toLocal8Bit().data() << ". Supposing it is a local folder..." << std::endl;
switch(errno) {
case EACCES:
std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl;
break;
case EFAULT:
std::cerr << "Buf or path points to an invalid address" << std::endl;
break;
case EINTR:
std::cerr << "This call was interrupted by a signal" << std::endl;
break;
case EIO:
std::cerr << "I/O Error" << std::endl;
break;
case ELOOP:
std::cerr << "Too many symlinks" << std::endl;
break;
case ENAMETOOLONG:
std::cerr << "path is too long" << std::endl;
break;
case ENOENT:
std::cerr << "The file referred by path does not exist" << std::endl;
break;
case ENOMEM:
std::cerr << "Insufficient kernel memory" << std::endl;
break;
case ENOSYS:
std::cerr << "The file system does not detect this call" << std::endl;
break;
case ENOTDIR:
std::cerr << "A component of the path is not a directory" << std::endl;
break;
case EOVERFLOW:
std::cerr << "Some values were too large to be represented in the struct" << std::endl;
break;
default:
std::cerr << "Unknown error" << std::endl;
}
std::cerr << "Errno: " << errno << std::endl;
return false;
}
}
#endif
public:
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
filters << "*.torrent";
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder()));
}
FileSystemWatcher(QString path, QObject *parent): QFileSystemWatcher(parent) {
filters << "*.torrent";
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder()));
addPath(path);
}
~FileSystemWatcher() {
#ifndef Q_WS_WIN
if(watch_timer)
delete watch_timer;
#endif
}
QStringList directories() const {
#ifndef Q_WS_WIN
if(watch_timer)
return QStringList(watched_folder.path());
#endif
return QFileSystemWatcher::directories();
}
void addPath(const QString & path) {
#ifndef Q_WS_WIN
watched_folder = QDir(path);
if(!watched_folder.exists()) return;
// Check if the path points to a network file system or not
if(isNetworkFileSystem(path)) {
// Network mode
Q_ASSERT(!watch_timer);
qDebug("Network folder detected: %s", path.toLocal8Bit().data());
qDebug("Using file polling mode instead of inotify...");
// Set up the watch timer
watch_timer = new QTimer(this);
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanFolder()));
watch_timer->start(5000); // 5 sec
} else {
#endif
// Normal mode
QFileSystemWatcher::addPath(path);
scanFolder();
#ifndef Q_WS_WIN
}
#endif
}
void removePath(const QString & path) {
#ifndef Q_WS_WIN
if(watch_timer) {
// Network mode
if(QDir(path) == watched_folder) {
delete watch_timer;
}
} else {
#endif
// Normal mode
QFileSystemWatcher::removePath(path);
#ifndef Q_WS_WIN
}
#endif
}
protected slots:
// XXX: Does not detect file size changes to improve performance.
void scanFolder() {
QStringList torrents;
if(watch_timer)
torrents = watched_folder.entryList(filters, QDir::Files, QDir::Unsorted);
else
torrents = QDir(QFileSystemWatcher::directories().first()).entryList(filters, QDir::Files, QDir::Unsorted);
if(!torrents.empty())
emit torrentsAdded(torrents);
}
signals:
void torrentsAdded(QStringList &pathList);
};
#endif // FILESYSTEMWATCHER_H

3
src/src.pro

@ -184,7 +184,8 @@ HEADERS += GUI.h \
TransferListDelegate.h \ TransferListDelegate.h \
TransferListFiltersWidget.h \ TransferListFiltersWidget.h \
propertieswidget.h \ propertieswidget.h \
TorrentFilesModel.h TorrentFilesModel.h \
filesystemwatcher.h
FORMS += MainWindow.ui \ FORMS += MainWindow.ui \
options.ui \ options.ui \
about.ui \ about.ui \

Loading…
Cancel
Save