/*******************************************************************
Part of the Fritzing project - http://fritzing.org
Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
Fritzing 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 3 of the License, or
(at your option) any later version.
Fritzing 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 for more details.
You should have received a copy of the GNU General Public License
along with Fritzing. If not, see .
********************************************************************
$Revision: 6904 $:
$Author: irascibl@gmail.com $:
$Date: 2013-02-26 16:26:03 +0100 (Di, 26. Feb 2013) $
********************************************************************/
#include "lockmanager.h"
#include "folderutils.h"
#include "textutils.h"
#include
#include
#include
#include
#include
const QString LockManager::LockedFileName = "___lockfile___.txt";
const long LockManager::FastTime = 2000;
const long LockManager::SlowTime = 240000;
static LockManager TheLockManager;
static QHash > TheTimers;
static QMultiHash TheLockedFiles;
static QMutex TheMutex;
LockedFile::LockedFile(const QString & filename, long freq) {
file.setFileName(filename);
frequency = freq;
}
bool LockedFile::touch() {
if (file.open(QFile::WriteOnly)) {
file.write("a");
file.close();
return true;
}
return false;
}
/////////////////////////////////////////////////
LockManager::LockManager() : QObject()
{
}
LockManager::~LockManager()
{
foreach (QTimer * timer, TheTimers) {
if (timer) timer->stop();
}
TheTimers.clear();
}
void LockManager::cleanup() {
foreach (QTimer * timer, TheTimers) {
if (timer) {
timer->stop();
delete timer;
}
}
TheTimers.clear();
}
void LockManager::touchFiles() {
QTimer * timer = qobject_cast(sender());
if (timer == NULL) return;
QMutexLocker locker(&TheMutex);
foreach (LockedFile * lockedFile, TheLockedFiles.values(timer->interval())) {
lockedFile->touch();
}
}
void LockManager::initLockedFiles(const QString & prefix, QString & folder, QHash & lockedFiles, long touchFrequency) {
// first create our own unique folder and lock it
QDir backupDir(FolderUtils::getUserDataStorePath(prefix));
QString lockedSubfolder = TextUtils::getRandText();
backupDir.mkdir(lockedSubfolder);
folder = backupDir.absoluteFilePath(lockedSubfolder);
if (touchFrequency > 0) {
LockedFile * lockedFile = makeLockedFile(folder + "/" + LockedFileName, touchFrequency);
lockedFiles.insert(lockedSubfolder, lockedFile);
}
}
LockedFile * LockManager::makeLockedFile(const QString & path, long touchFrequency) {
LockedFile * lockedFile = new LockedFile(path, touchFrequency);
lockedFile->touch();
TheMutex.lock();
TheLockedFiles.insert(touchFrequency, lockedFile);
TheMutex.unlock();
QTimer * timer = TheTimers.value(touchFrequency, NULL);
if (timer == NULL) {
timer = new QTimer();
timer->setInterval(touchFrequency);
timer->setSingleShot(false);
QObject::connect(timer, SIGNAL(timeout()), &TheLockManager, SLOT(touchFiles()));
timer->start();
TheTimers.insert(touchFrequency, timer);
}
return lockedFile;
}
void LockManager::releaseLockedFiles(const QString & folder, QHash & lockedFiles)
{
// remove backup files; this is a clean exit
releaseLockedFiles(folder, lockedFiles, true);
}
void LockManager::releaseLockedFiles(const QString & folder, QHash & lockedFiles, bool remove)
{
QDir backupDir(folder);
backupDir.cdUp();
foreach (QString sub, lockedFiles.keys()) {
LockedFile * lockedFile = lockedFiles.value(sub);
TheMutex.lock();
TheLockedFiles.remove(lockedFile->frequency, lockedFile);
TheMutex.unlock();
if (remove) {
FolderUtils::rmdir(backupDir.absoluteFilePath(sub));
}
delete lockedFile;
}
lockedFiles.clear();
}
void LockManager::checkLockedFiles(const QString & prefix, QFileInfoList & backupList, QHash & lockedFiles, bool recurse, long touchFrequency)
{
QDir backupDir(FolderUtils::getUserDataStorePath(prefix));
QFileInfoList dirList = backupDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::NoSymLinks);
foreach (QFileInfo dirInfo, dirList) {
QDir dir(dirInfo.filePath());
QStringList filters;
//DebugDialog::debug(QString("looking in backup dir %1").arg(dir.absolutePath()));
QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files | QDir::Hidden | QDir::NoSymLinks);
bool gotRecurse = false;
if (recurse && fileInfoList.isEmpty()) {
gotRecurse = checkLockedFilesAux(dir, filters);
}
if (fileInfoList.isEmpty() && !gotRecurse) {
// could mean this backup folder is just being created by another process
// could also mean it's leftover crap.
// check the date and only delete if it's old
QDateTime lastModified = dirInfo.lastModified();
if (lastModified < QDateTime::currentDateTime().addMSecs(-2000 - touchFrequency)) {
FolderUtils::rmdir(dirInfo.filePath());
}
continue;
}
QFileInfo lockInfo(dir.absoluteFilePath(LockedFileName));
if (lockInfo.exists()) {
QDateTime lastModified = lockInfo.lastModified();
if (lastModified >= QDateTime::currentDateTime().addMSecs(-2000 - touchFrequency)) {
// somebody else owns the file
continue;
}
}
// we own the file
QString folder;
LockedFile * lockedFile = makeLockedFile(dir.absoluteFilePath(LockedFileName), touchFrequency);
lockedFiles.insert(dirInfo.fileName(), lockedFile);
foreach (QFileInfo fileInfo, fileInfoList) {
backupList << fileInfo;
}
}
}
bool LockManager::checkLockedFilesAux(const QDir & parent, QStringList & filters)
{
QFileInfoList dirList = parent.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::NoSymLinks);
foreach (QFileInfo dirInfo, dirList) {
QDir dir(dirInfo.filePath());
//DebugDialog::debug(QString("looking in backup dir %1").arg(dir.absolutePath()));
QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files | QDir::Hidden | QDir::NoSymLinks);
if (!fileInfoList.isEmpty()) return true;
if (checkLockedFilesAux(dir, filters)) return true;
}
return false;
}