KDECore
kmemfile.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kmemfile.h"
00022
00023 #include <QtCore/QSharedMemory>
00024 #include <QtCore/QCryptographicHash>
00025 #include <QtCore/QFile>
00026 #include <QtCore/QDir>
00027
00028 #include "klocalizedstring.h"
00029
00030 class KMemFile::Private
00031 {
00032 public:
00033 struct sharedInfoData {
00034 int shmCounter;
00035 qint64 shmDataSize;
00036
00037 sharedInfoData() {
00038 memset ( this, 0, sizeof ( this ) );
00039 }
00040 };
00041 Private ( KMemFile *_parent ) : readWritePos ( 0 ), shmDataSize ( 0 ), parent ( _parent ) {}
00042
00043 QString getShmKey ( int iCounter = -1 );
00044 static QString getShmKey ( const QString &filename, int iCounter = -1 );
00045 bool loadContentsFromFile();
00046 void close();
00047
00048 QString filename;
00049 QSharedMemory shmInfo;
00050 QSharedMemory shmData;
00051 qint64 readWritePos;
00052 qint64 shmDataSize;
00053
00054 KMemFile *parent;
00055 };
00056
00057 QString KMemFile::Private::getShmKey ( int iCounter )
00058 {
00059 return getShmKey ( filename, iCounter );
00060 }
00061
00062 QString KMemFile::Private::getShmKey ( const QString &filename, int iCounter )
00063 {
00064 QByteArray tmp = QString ( QDir ( filename ).canonicalPath() + QString::number ( iCounter ) ).toUtf8();
00065 return QString::fromAscii ( QCryptographicHash::hash ( tmp, QCryptographicHash::Sha1 ) );
00066 }
00067
00068 bool KMemFile::Private::loadContentsFromFile()
00069 {
00070 QFile f ( filename );
00071 if ( !f.exists() ) {
00072 close();
00073 parent->setErrorString ( i18n ( "File %1 does not exist" , filename ) );
00074 return false;
00075 }
00076 if ( !f.open ( QIODevice::ReadOnly ) ) {
00077 close();
00078 parent->setErrorString ( i18n ( "Cannot open %1 for reading" , filename ) );
00079 return false;
00080 }
00081
00082 sharedInfoData *infoPtr = static_cast<sharedInfoData*> ( shmInfo.data() );
00083
00084 infoPtr->shmDataSize = f.size();
00085 shmData.setKey ( getShmKey ( infoPtr->shmCounter ) );
00086 if ( !shmData.create ( infoPtr->shmDataSize ) ) {
00087 close();
00088 parent->setErrorString ( i18n ( "Cannot create memory segment for file %1" , filename ) );
00089 return false;
00090 }
00091 shmData.lock();
00092 qint64 size = 0;
00093 qint64 bytesRead;
00094 char *data = static_cast<char*> ( shmData.data() );
00095 bytesRead = f.read ( data, infoPtr->shmDataSize );
00096 if ( bytesRead != infoPtr->shmDataSize ) {
00097 close();
00098 parent->setErrorString ( i18n ( "Could not read data from %1 into shm" , filename ) );
00099 return false;
00100 }
00101 shmDataSize = size;
00102 shmData.unlock();
00103 return true;
00104 }
00105
00106 void KMemFile::Private::close()
00107 {
00108 shmData.unlock();
00109 shmData.detach();
00110 shmInfo.unlock();
00111 shmInfo.detach();
00112 readWritePos = 0;
00113 shmDataSize = 0;
00114 }
00115
00116 KMemFile::KMemFile ( const QString &filename, QObject *parent )
00117 : QIODevice ( parent ), d ( new Private ( this ) )
00118 {
00119 d->filename = filename;
00120 }
00121
00122 KMemFile::~KMemFile()
00123 {
00124 close();
00125 delete d;
00126 }
00127
00128 void KMemFile::close ()
00129 {
00130 QIODevice::close();
00131 if ( !isOpen() )
00132 return;
00133 d->close();
00134 }
00135
00136 bool KMemFile::isSequential () const
00137 {
00138 return false;
00139 }
00140
00141 bool KMemFile::open ( OpenMode mode )
00142 {
00143 if ( isOpen() ) {
00144 QIODevice::open ( mode );
00145 return false;
00146 }
00147
00148 if ( mode != QIODevice::ReadOnly ) {
00149 setErrorString ( i18n ( "Only 'ReadOnly' allowed" ) );
00150 return false;
00151 }
00152
00153 if ( !QFile::exists ( d->filename ) ) {
00154 setErrorString ( i18n ( "File %1 does not exist" , d->filename ) );
00155 return false;
00156 }
00157
00158 QSharedMemory lock ( QDir ( d->filename ).canonicalPath() );
00159 lock.lock();
00160
00161 Private::sharedInfoData *infoPtr;
00162 d->shmInfo.setKey ( d->getShmKey() );
00163
00164 if ( !d->shmInfo.attach ( QSharedMemory::ReadWrite ) ) {
00165 if ( !d->shmInfo.create ( sizeof ( Private::sharedInfoData ) ) ) {
00166 lock.unlock();
00167 setErrorString ( i18n ( "Cannot create memory segment for file %1" , d->filename ) );
00168 return false;
00169 }
00170 d->shmInfo.lock();
00171
00172 infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() );
00173 memset ( infoPtr, 0, sizeof ( Private::sharedInfoData ) );
00174 infoPtr->shmCounter = 1;
00175 if ( !d->loadContentsFromFile() ) {
00176 d->shmInfo.unlock();
00177 d->shmInfo.detach();
00178 lock.unlock();
00179 return false;
00180 }
00181 } else {
00182 d->shmInfo.lock();
00183 infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() );
00184 d->shmData.setKey ( d->getShmKey ( infoPtr->shmCounter ) );
00185 if ( !d->shmData.attach ( QSharedMemory::ReadOnly ) ) {
00186 if ( !d->loadContentsFromFile() ) {
00187 d->shmInfo.unlock();
00188 d->shmInfo.detach();
00189 lock.unlock();
00190 return false;
00191 }
00192 }
00193 }
00194 d->shmDataSize = infoPtr->shmDataSize;
00195 d->shmInfo.unlock();
00196 lock.unlock();
00197
00198 setOpenMode ( mode );
00199 return true;
00200 }
00201
00202 bool KMemFile::seek ( qint64 pos )
00203 {
00204 if ( d->shmDataSize < pos ) {
00205 setErrorString ( i18n ( "Cannot seek past eof" ) );
00206 return false;
00207 }
00208 d->readWritePos = pos;
00209 QIODevice::seek ( pos );
00210 return true;
00211 }
00212
00213 qint64 KMemFile::size () const
00214 {
00215 return d->shmDataSize;
00216 }
00217
00218 qint64 KMemFile::readData ( char * data, qint64 maxSize )
00219 {
00220 if ( ( openMode() & QIODevice::ReadOnly ) == 0 )
00221 return -1;
00222
00223 qint64 maxRead = size() - d->readWritePos;
00224 qint64 bytesToRead = qMin ( maxRead, maxSize );
00225 const char *src = static_cast<const char*> ( d->shmData.data() );
00226 memcpy ( data, &src[d->readWritePos], bytesToRead );
00227 d->readWritePos += bytesToRead;
00228 return bytesToRead;
00229 }
00230
00231 qint64 KMemFile::writeData ( const char *, qint64 )
00232 {
00233 return -1;
00234 }
00235
00236 void KMemFile::fileContentsChanged ( const QString &filename )
00237 {
00238 QSharedMemory lock ( QDir ( filename ).canonicalPath() );
00239 lock.lock();
00240
00241 QSharedMemory shmData ( Private::getShmKey ( filename ) );
00242 if ( !shmData.attach() )
00243 return;
00244 shmData.lock();
00245 Private::sharedInfoData *infoPtr = static_cast<Private::sharedInfoData*> ( shmData.data() );
00246 infoPtr->shmCounter++;
00247 infoPtr->shmDataSize = 0;
00248 shmData.unlock();
00249 }