/* 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 #include #include "smdirwatcher.h" #include "smtreeitem.h" #include "helper.h" extern int errno; SmDirWatcher::SmDirWatcher(QObject *parent) : QThread(parent), mFd(0), mDescr(0) { mBufLen = 1024 * (sizeof(struct inotify_event) + 16); mINdata = new char[mBufLen]; mFd = inotify_init(); mCollector = new SmDataColletor(8, this); mSemFree = new QSemaphore(1024); mSemUsed = new QSemaphore; mDataQueue = new QQueue >(); mCollector->init(mSemFree, mSemUsed, mDataQueue); mCollector->start(); } SmDirWatcher::~SmDirWatcher(){ if(mFd && mDescr){ inotify_rm_watch(mFd, mDescr); } delete mINdata; } void SmDirWatcher::setDir(const QString &dir){ if(mDescr){ inotify_rm_watch(mFd, mDescr); //generates IN_IGNORE ??? } /* 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_MODIFY | IN_MOVED_FROM | IN_MOVED_TO); mCurrent = dir; mSemFree->acquire(); QPair c = qMakePair(dir, Populate); mDataQueue->enqueue(c); mSemUsed->release(); } void SmDirWatcher::run(){ 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; } mSemFree->acquire(); quint32 mask = e->mask; QString name = QString("%1/%2").arg(mCurrent).arg(e->name); DWEvent curEvent = None; if(mask & IN_CREATE || mask & IN_MOVED_TO){ curEvent = Added; } if(mask & IN_DELETE || mask & IN_MOVED_FROM){ curEvent = Deleted; } if(mask & IN_CLOSE_WRITE || e->mask & IN_MODIFY){ curEvent = Modified; } QPair c = qMakePair(name, curEvent); mDataQueue->enqueue(c); mSemUsed->release(); i += sizeof(inotify_event) + e->len; } } SmDataColletor::SmDataColletor(const int numFields, QObject *parent) : QThread(parent), mSemFree(0), mSemUsed(0), mDataQueue(0), mNumFields(numFields) {} void SmDataColletor::init(QSemaphore *set, QSemaphore *get, QQueue > *data){ mSemFree = set; mSemUsed = get; mDataQueue = data; } void SmDataColletor::run(){ forever { mSemUsed->acquire(); QPair cur = mDataQueue->dequeue(); if(cur.second == SmDirWatcher::Populate){ SmTreeItem *i = populate(cur.first); emit population(i); mSemFree->release(); continue; } QFileInfo fi(cur.first); QList fd = fileData(fi); emit newData(fd, cur.second); mSemFree->release(); } } SmTreeItem * SmDataColletor::populate(const QString &dir){ SmTreeItem *retval = new SmTreeItem(mNumFields); QDir d = QDir(dir); foreach(QFileInfo fi, d.entryInfoList()){ if(fi.fileName() == "."){ continue; } QList data = fileData(fi); SmTreeItem *newItem = new SmTreeItem(data, retval); retval->appendChild(newItem); } return retval; } const QList SmDataColletor::fileData(const QFileInfo &fi) const{ QList data; data << fi.fileName() << fi.size(); QString mime = Helper::mimeType(fi.absoluteFilePath()); data << mime; data << fi.lastModified(); QList si = QList() << QVariant() << QVariant(); if(mime.startsWith("video")){ si = Helper::duration(fi.absoluteFilePath()); } data << Helper::md5Sum(fi.absoluteFilePath()); data << si << fi.absoluteFilePath(); return data; }