/* 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 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include "smdirmodel.h" #include "smdirwatcher.h" #include "smtreeitem.h" #include "helper.h" #include "smglobals.h" SmDirWatcher::SmDirWatcher(int numFields, QObject *parent) : QThread(parent), mFd(0), mDescr(0), mNumFields(numFields), mExpensiveOps(true) { mBufLen = 1024 * (sizeof(struct inotify_event) + 16); mINdata = new char[mBufLen]; mFd = inotify_init(); mDb = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), "dirwatcherdb"); mDb.open(); } void SmDirWatcher::setDir(const QString &dir){ if(mDescr){ inotify_rm_watch(mFd, mDescr); //generates IN_IGNORE ??? } mCurrent = dir; QDir d(mCurrent); qApp->setOverrideCursor(Qt::WaitCursor); SmTreeItem *rootItem = new SmTreeItem(mNumFields); for(uint i = 0; i < d.count(); ++i){ QFileInfo fi = d.entryInfoList().at(i); if(fi.fileName() == "." || fi.fileName() == ".."){ continue; } QList data = generalData(fi.absoluteFilePath()); SmTreeItem *newItem = new SmTreeItem(data, rootItem); rootItem->appendChild(newItem); } emit population(rootItem); /* mask rationale: * IN_DELETE_SELF cannot happen since we're only * watching one directory at all time. * We don't care about the other events */ mDescr = inotify_add_watch(mFd, qPrintable(dir), IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO); qApp->restoreOverrideCursor(); } void SmDirWatcher::setExpensiveOps(bool expensiveOps){ mExpensiveOps = expensiveOps; } QList SmDirWatcher::generalData(const QString &path){ QFileInfo fi(path); QList data; data << fi.fileName() << fi.size(); QString mime = Helper::mimeType(fi.absoluteFilePath()); data << mime; data << fi.lastModified(); QString md5; if(mExpensiveOps){ md5 = Helper::md5Sum(path); data << md5; if(mime.startsWith("video")){ QVariantMap m = Helper::ffmpegData(fi.absoluteFilePath()); data << m.value("duration") << m.value("bit_rate"); }else if(mime.startsWith("image")){ if(fi.size() > 1024*400){ //skip images bigger than 300 kb data << "skipped" << QVariant(); }else{ QVariant picSize = Helper::picSize(fi.absoluteFilePath()); data << picSize << QVariant(); } }else{ data << QVariant() << QVariant(); } data << fi.absoluteFilePath(); int present = presenceData(md5); data << present; }else{ data << QVariant() << QVariant() << QVariant() << fi.absoluteFilePath() << SmDirModel::InNone; } return data; } int SmDirWatcher::presenceData(QString &md5){ int retval = SmDirModel::InNone; QSqlQuery present1Q(mDb); present1Q.prepare("SELECT COUNT(*) FROM files WHERE cmd5sum = :md5"); present1Q.bindValue(":md5", md5); if(!present1Q.exec()){ mDb.close(); mDb.open(); return SmDirModel::InNone; } while(present1Q.next()){ int c = present1Q.value(0).toInt(); if(c > 0){ retval = SmDirModel::InFiles; } } QSqlQuery present2Q(mDb); present2Q.prepare("SELECT COUNT(*) from files_origin WHERE cmd5sum = :md5"); present2Q.bindValue(":md5", md5); present2Q.exec(); while(present2Q.next()){ int c = present2Q.value(0).toInt(); if(c > 0){ retval = SmDirModel::InOrigin; } } QSqlQuery present3Q(mDb); present3Q.prepare("SELECT COUNT(*) FROM pics WHERE cmd5sum = :md5"); present3Q.bindValue(":md5", md5); present3Q.exec(); while(present3Q.next()){ int c = present3Q.value(0).toInt(); if(c > 0){ retval = SmDirModel::InPictures; } } return retval; } void SmDirWatcher::run(){ struct pollfd pfd[1]; pfd[0].fd = mFd; pfd[0].events = POLLIN; pfd[0].revents = 0; int pr = poll(pfd, 1, 0); if(pr <= 0){ return; } int r = read(mFd, mINdata, mBufLen); if(r <= 0){ return; } int i = 0; while(i < r){ inotify_event *e = reinterpret_cast(&mINdata[i]); if((!e->len) || (e->mask & IN_IGNORED)){ i += sizeof(inotify_event) + e->len; continue; } quint32 mask = e->mask; QString name = QString("%1/%2").arg(mCurrent).arg(e->name); QList d = generalData(name); if(mask & IN_CREATE || mask & IN_MOVED_TO){ emit newData(d, Added); }else if(mask & IN_DELETE || mask & IN_MOVED_FROM){ emit newData(d, Deleted); }else if(mask & IN_CLOSE_WRITE){ emit newData(d, CloseWrite); } i += sizeof(inotify_event) + e->len; } } void SmDirWatcher::stop(){ quit(); wait(); }