summaryrefslogtreecommitdiffstats
path: root/smdirwatcher.cpp
blob: a216af5280b44ac5ceff0e56deaace484ec34129 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
  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 <QVarLengthArray>
#include <QMutexLocker>

#include <sys/inotify.h>
#include <stropts.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>

#include "smdirwatcher.h"

extern int errno;

SmDirWatcher::SmDirWatcher(QObject *parent) : QThread(parent), mFd(0), mDescr(0) {
    mFd = inotify_init1(IN_NONBLOCK);
}

SmDirWatcher::~SmDirWatcher(){
    if(mFd && mDescr){
        inotify_rm_watch(mFd, mDescr);
    }
}

void SmDirWatcher::setDir(const QString &dir){
    QMutexLocker lock(&mWatchMx);
    if(mDescr){
        inotify_rm_watch(mFd, mDescr); //generates IN_IGNORE ???
    }
    /* mask rationale:
     * IN_DELETE_SELF, IN_MOVE_TO and IN_MOVE_FROM cannot happen,
     * since we're only watching one directory at all times
     * don't care about the other events
     */
    mDescr = inotify_add_watch(mFd, qPrintable(dir), IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MODIFY);
    mCurrent = dir;
}

#include <QDebug>

void SmDirWatcher::run(){
    QMutexLocker lock(&mWatchMx);
    QVarLengthArray<char, 4096> data(ioctl(mFd, FIONREAD) + 1);
    int r = read(mFd, data.data(), data.size());
    while(r < 0){
        int err = errno;
        // buffer too small
        if(err == EINVAL){
            data.resize(data.size() * 2);
            r = read(mFd, data.data(), data.size());
            continue;
        // dunno
        }else{
            return;
        }
    }
    // inspect data
    char *at = data.data();
    char *end = at + data.size();
    while(at < end){
        inotify_event *e = reinterpret_cast<inotify_event*>(at);
        qDebug() << "inotify:" << e->name;
        if(e->mask & IN_IGNORED){
            at += sizeof(inotify_event) + e->len;
            continue;
        }
        if(e->mask & IN_CREATE){
            emit dwEvent(e->name, Added);
        }
        if(e->mask & IN_DELETE){
            emit dwEvent(e->name, Deleted);
        }
        if((e->mask & IN_CLOSE_WRITE) || (e->mask & IN_MODIFY)){
            emit dwEvent(e->name, Modified);
        }
        at += sizeof(inotify_event) + e->len;
    }
}