/****************************************************************************
**
** Copyright (C) 2003-2006 Frank Hemer <frank@hemer.org>,
** Tilo Riemer <riemer@crossvc.com>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt
** CrossVC is released under the terms of the
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification,
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
** different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
** products derived from this software without specific prior written
** permission.
** 4. The source code is the creative property of the authors.
** Extensions and development under the terms of the Gnu Public License
** are limited to the Unix platform. Any distribution or compilation of
** the source code against libraries licensed other than gpl requires
** the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** 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, version 2 of the License.
** This program is distributed in
** the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE.
**
** See the GNU General Public License version 2 for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include "config.h"
#include "globals.h"
#include "FamConnector.h"
#include <fcntl.h>
#include <qsocketnotifier.h>
#include <qapplication.h>
#include <qdir.h>
#define MAXDIRS 20000
FamConnector::FamConnector() : DirConnector(), famConnection(NULL), socketNotifier(NULL), initiated(false), m_dirCount(0) {
// Connect to fam (say FAMConnection *famConnection is a member of our class)
famConnection = new FAMConnection;
if (FAMOpen2(famConnection, "LinCVS") != 0) {
delete famConnection;
famConnection = NULL;
return;
}
// Set the connection to be non-blocking
int famfd = FAMCONNECTION_GETFD(famConnection);
int flags = fcntl(famfd, F_GETFL);
fcntl(famfd, F_SETFL, flags | O_NONBLOCK);
socketNotifier = new QSocketNotifier(famfd, QSocketNotifier::Read, 0);
connect(socketNotifier, SIGNAL(activated(int)), SLOT(readFam()));
initiated = true;
setRunning(true);
qDebug("fam initiated");
}
FamConnector::~FamConnector() {
setRunning(false);
disconnect();
if (socketNotifier) {
socketNotifier->setEnabled(false);
}
if (famConnection) {
FAMClose(famConnection);
delete famConnection;
famConnection = NULL;
}
}
void FamConnector::readFam() {
// We want to read as many events as are available.
while (FAMPending(famConnection)) {
// qDebug("fam pending");
FAMEvent famEvent;
if (FAMNextEvent(famConnection, &famEvent) != 1) {
disconnect();
if (socketNotifier) {
socketNotifier->setEnabled(false);
if (famConnection) {
FAMClose(famConnection);
delete famConnection;
famConnection = NULL;
}
}
qDebug("fam error"+QString::number(FAMErrno));
qDebug("In words: "+QString(FamErrlist[FAMErrno]));
DirWatch::b_isActive = FALSE;
return;
}
// qDebug("FamEvent: "+QString::number(famEvent.fr.reqnum));
famData * data = (famData*)famEvent.userdata;
if (!data) {
// qDebug("continueing .... event: "+QString(famEvent.filename));
continue;//allready released
} else {
// qDebug("event: "+QString(famEvent.filename)+", id: "+QString::number(famEvent.code));
}
QString fileName = QString::null;
bool deleted = FALSE;
if (famEvent.code == FAMChanged) {
// qDebug("change-event: "+QString(famEvent.filename)+", userdata: "+data->dir->fullName()+", val: "+QString::number(famEvent.code));
if ( bugfixList.findIndex(famEvent.fr.reqnum) == -1) {
debug("trouble: old dir data should have been removed: "+QString(famEvent.filename)+", req: "+QString::number(famEvent.fr.reqnum));
FAMRequest req;
req.reqnum = famEvent.fr.reqnum;
if (!FAMCancelMonitor(famConnection, &req)) {
qDebug("successfully remove from fam: "+QString::number(famEvent.fr.reqnum));
return;
} else {
qDebug("remove from fam failed for req: "+QString::number(famEvent.fr.reqnum));
}
}
else {
addToDirQueue(data->dir, fileName, deleted);
}
} else if (famEvent.code == FAMAcknowledge) {
// qDebug("deleting: "+QString(famEvent.filename)+", id: "+QString::number(famEvent.fr.reqnum));
delete data;
famEvent.userdata = 0;
}
}
}
bool FamConnector::addMonitoredDir(DirBase * dir) {
if (!initiated) {
qDebug("trying to add: "+dir->fullName()+" but fam not initiated");
return FALSE;
}
if (m_dirCount >= MAXDIRS) {
qDebug("max fd count reached, switching to LinCVS polling");
QDictIterator<famData> it( famNames );
for ( ; it.current(); ++it ) {
int id;
do {
id = it.current()->id;
releaseMonitoredDir(it.current()->dir);
} while (it.current() && (id != it.current()->id) );
}
return FALSE;
}
FAMRequest req;
famData * data = new famData();
data->dir = dir;
QString name = dir->fullName();
if (!FAMMonitorFile( famConnection, name.latin1(), &req, data)) {
data->id = req.reqnum;
famNames.insert(name,data);
bugfixList.append(req.reqnum);
qApp->processEvents();//fam will crash if its queues get filled up
++m_dirCount;
return TRUE;
}
data->dir = NULL;
delete data;
return FALSE;
}
void FamConnector::releaseMonitoredDir(DirBase * dir) {
if (!initiated) {
qDebug("trying to release: "+dir->fullName()+", but fam not initiated");
return;
}
FAMRequest req;
famData * data = NULL;
QString name = dir->fullName();
data = famNames.find(name);
if (data) {
req.reqnum = data->id;
if (!FAMCancelMonitor(famConnection, &req)) {
famNames.remove(name);
const int idx = data->id;
bugfixList.remove(idx);
qApp->processEvents();//fam will crash if its queues get filled up
--m_dirCount;
} else {
qDebug("release failed on: "+name);
}
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1