[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Fwd: [Kde-pim] KSharedFile RFC
From:       Holger Freyther <freyther () gmx ! net>
Date:       2001-12-22 20:18:02
[Download RAW message or body]

Hi KDE-Core,
kdepim needs/needed a way for locking a file. This is needed for syncing 
files. KitchenSync will most likely depend on it. Kabc is currently using the 
method and could make use of KSharedFile. Because kabc is inside kdelibs and 
will depend on KSharedFile I wanted to ask if you guys have any complains 
what ever. I thought of  putting it in kio. 
Cornelius pointed out he doesn't like the name tryLockFile and prefers 
request(Save)Ticket but this is a minor details.
Locking works thanks to the atomic link(2) operation. This is the only method 
that works across nfs. I know of flock(2) and others but I think this way is 
the best.
My position was I didn't want to rely on DCOP (KDirWatcher) and so I did my 
own checking. I was about to create a KFileWatcher but skipped it

Any comments?

regards Holger 

----------  Weitergeleitete Nachricht  ----------

Subject: [Kde-pim] KSharedFile RFC
Date: Sun, 16 Dec 2001 18:12:22 +0100
From: Holger Freyther <freyther@gmx.net>
To: kde-pim@mail.kde.org
Cc: Cornelius Schumacher <lists@cornelius-schumacher.de>

Hi Cornelius, kde-pims,
Cornelius and me created KSharedFile. Cornelius I added all the stuff you
missed and I think my file is ready for committing. I would like to add it to
kio? Any comments>
KSharedFile is a class to share file access between processes. It gives api
to lock a file. Locking means no other process than the holder can write to
the file. This is done in 2 ways. First the holder needs to have a ticket and
the other is inside the class.

Actually I don't know what to say else

regards Holger

PS: Cornelius sorry it took so long. But I had to study and did some work for
kafka and kitchensync

-------------------------------------------------------



["ksharedfile.h" (text/x-c++)]

/* This file is part of the KDE libraries
    Copyright (C) 2001 Holger Freyther <freyher@kde.org>
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
		  
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

*/

#ifndef ksharedfile_h
#define ksharedfile_h

#include <sys/types.h>

#include <qstring.h>
#include <qobject.h>

class QFile;
class QTimer; 

/** The point of KSharedFile is to make it possible for more than one 
    program to work with a file. It take's care that only one program
    writes to the file at a time. There's no really way of pretending a
program to write to the file.
    The program creates a instance of KSharedFile and sets the FileName.
    If it want's to write to the file it calls tryLockFile( ) and either get's
    the lock or not.
    Then there are also signal which signalize a change.
    @short KSharedFile to lock a file
    @author Holger Freyther <freyther@kde.org>
    @version 0.5 
 */

class KSharedFile : public QObject 
{
  Q_OBJECT;
 public:
  /** Instantiate the class.
    @param filename The resource to be shared with others
   */
  KSharedFile( const QString &filename );
  /** this function is for convience 
      it does the same a above but takes a file as paramter
      @param file The file to be shared.
  */
  KSharedFile( const QFile &file );
  ~KSharedFile( );
  
  class Ticket
  {
      friend class KSharedFile;
      Ticket ( const QString &filename ) : m_fileName( filename ) {}
    private:
      QString m_fileName;

  };
  /** sets the Filename
      @param filename The name of the resource to be shared 
   */
  void setFileName( const QString &filename );
  /** This method is for convience.It sets the File
      @param file The file to be shared
   */
  void setFile( const QFile &file );
  /** @return the fileName of the shared file
   */
  QString fileName( ) const;

  /** This tries to lock the file. It returns right after trying either successful or not
 @return if Ticket is not equal to 0l the file was successfully locked
  */
  Ticket* tryLockFile( );
  /** This loads the file specified
     @see setFileName(const QString & )
   */
  QString load( );
  /** This writes to the file if the ticket is valid
 @param 
   */
  bool save( Ticket *ticket, const QString &string );
  /** after locking this unlocks the file
   */
  bool unlockFile( Ticket *ticket );
  /** check whether or not the file is locked
   @return the state of the lock
   */
  bool isLocked( );
  /**
     @returns whether or not I locked the file
   */
  bool didILock( );
  /** In future this will tell you who to blame for the file is locked.

   */
  QString whoHoldsLock( ) const;


 protected:
  QString m_uniqueName;

 private:
  QString m_fileName;
  bool m_locked:1;
  bool m_lockedOther:1;
  QTimer *m_FileCheckTimer;
  time_t m_ChangeTime;

 private slots:
  void checkFile( );
 signals:
  /**
    This signal get emitted when the file get unlocked
    @param filename The name of the file which gets locked
   */
  void fileUnlocked( const QString &filename);
  /** The file got locked
      @param filename filename got locked
  */  
  void fileLocked( const QString &filename );
  /**
      The file changed during a lock and unlock session
      @param filename The file with the name filenam changed
   */
  void fileChanged( const QString &filename );
};

#endif

["ksharedfile.cpp" (text/x-c)]

/* This file is part of the KDE libraries
    Copyright (C) 2001 Holger Freyther <freyher@kde.org>
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
		  
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

*/
#include <sys/stat.h>
#include <unistd.h>


#include <kapplication.h>
#include <kdebug.h>

#include <qfile.h>
#include <qtimer.h>
#include <qtextstream.h>
#include "ksharedfile.h"

KSharedFile::KSharedFile( const QString &filename ) : QObject( 0, "KSharedFile" )
{
  m_locked = false;
  m_FileCheckTimer = new QTimer (this );
  connect( m_FileCheckTimer, SIGNAL( timeout() ), SLOT( checkFile()) );
  setFileName( filename);
}
KSharedFile::KSharedFile( const QFile &file ) : QObject( 0, "KSharedFile" )
{
  m_locked = false;
  m_FileCheckTimer = new QTimer(this  );
  connect( m_FileCheckTimer, SIGNAL( timeout() ), SLOT( checkFile()) );
  setFile( file);
}
KSharedFile::~KSharedFile( )
{
  unlockFile(new Ticket(m_fileName) );
  delete m_FileCheckTimer; // qt would do this too
}

void KSharedFile::setFileName ( const QString &filename )
{
  unlockFile(new Ticket(m_fileName) );
  m_lockedOther = false;
  m_fileName = filename;
  struct stat s;
  int result = stat( QFile::encodeName( m_fileName ), &s );
  if ( result == 0 ) { // file exists 
    m_ChangeTime = s.st_ctime; // last change
    m_FileCheckTimer->start( 500 );
  }
}
void KSharedFile::setFile( const QFile &file )
{
  setFileName( file.name() );
}
QString KSharedFile::fileName( )const 
{
  return m_fileName;
}


KSharedFile::Ticket *KSharedFile::tryLockFile( )
{ 
  kdDebug(5910) << "KSharedFile::tryLockFile " << m_fileName << endl; 
  if(!QFile::exists( m_fileName ) ) return 0l;  
  if(QFile::exists( m_fileName+".lock") ) return 0l;
  QString lockFile(m_fileName + ".lock" );

  //create unique file
  m_uniqueName =  m_fileName + kapp->randomString(8) ;
  QFile file( m_uniqueName);
  file.open( IO_WriteOnly );
  file.close( );

  // Create lock file
  int result = link ( QFile::encodeName( m_uniqueName ),
		      QFile::encodeName( m_fileName + ".lock" ));
  if( result == 0 )
  {
    emit fileLocked(m_fileName );
    m_locked = true;
    return new KSharedFile::Ticket(m_fileName );
  }
  return 0l;
}

bool KSharedFile::unlockFile( Ticket* ticket )
{
  if( m_locked && ticket->m_fileName==m_fileName){
    m_locked = false;
    unlink( QFile::encodeName(m_fileName+ ".lock") );
    QFile::remove( m_uniqueName );
    emit fileUnlocked( m_fileName );   
    delete ticket;
    ticket=0;
    return true;
  }else
    return false;
}
bool KSharedFile::isLocked( )
{
  //return m_locked;
  return QFile::exists(m_fileName + ".lock");
}
bool KSharedFile::didILock( )
{
  return m_locked;
}
QString KSharedFile::whoHoldsLock( ) const
{
  return QString();
}
bool KSharedFile::save( Ticket *ticket, const QString &string )
{
  if ( m_locked && ticket->m_fileName == m_fileName ){
    QFile file( m_fileName ); // handles unicode names inernal
    file.open(IO_WriteOnly);
    QTextStream stream( &file );
    //file.writeBlock( string ); //doesn't work
    stream << string;
    file.close();
    return true;
  }
  return false;
}
QString KSharedFile::load( )
{
  QString dummy;
  QFile file( m_fileName );
  file.open(IO_ReadOnly);
  dummy = QString(file.readAll() );
  file.close();
  return dummy;
}
void KSharedFile::checkFile( )
{ 
  // ok somebody holds the lock
  if( !m_lockedOther && !m_locked && QFile::exists( QFile::encodeName( m_fileName+ ".lock" ) ) ) {
    emit fileLocked( m_fileName );
    m_lockedOther= true; // other locked our file
    return; 
  }
  else if( m_lockedOther && !m_locked &&!QFile::exists( QFile::encodeName( m_fileName + ".lock" ) ) ) {
    emit fileUnlocked( m_fileName );
    m_lockedOther = false; // other
   
  }  
  struct stat s;
  int result = stat( QFile::encodeName( m_fileName ), &s );
  if ( result == 0 && (m_ChangeTime != s.st_ctime ) ){
    m_ChangeTime = s.st_ctime;
    emit fileChanged( m_fileName );
  }
  
}

#include "ksharedfile.moc"


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic