KDECore
ksavefile.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
00022
00023
00024 #include "ksavefile.h"
00025
00026 #include <config.h>
00027
00028 #include <QtCore/QDir>
00029 #include <QProcess>
00030 #include <QTemporaryFile>
00031
00032 #include <kconfig.h>
00033 #include <kde_file.h>
00034 #include <klocale.h>
00035 #include <kstandarddirs.h>
00036 #include <kconfiggroup.h>
00037 #include <kcomponentdata.h>
00038
00039 class KSaveFile::Private
00040 {
00041 public:
00042 QString realFileName;
00043 QString tempFileName;
00044
00045 QFile::FileError error;
00046 QString errorString;
00047 bool wasFinalized;
00048 FILE *stream;
00049 KComponentData componentData;
00050
00051 Private(const KComponentData &c)
00052 : componentData(c)
00053 {
00054 error = QFile::NoError;
00055 wasFinalized = false;
00056 stream = 0;
00057 }
00058 };
00059
00060 KSaveFile::KSaveFile()
00061 : d(new Private(KGlobal::mainComponent()))
00062 {
00063 }
00064
00065 KSaveFile::KSaveFile(const QString &filename, const KComponentData &componentData)
00066 : d(new Private(componentData))
00067 {
00068 KSaveFile::setFileName(filename);
00069 }
00070
00071 KSaveFile::~KSaveFile()
00072 {
00073 if (!d->wasFinalized)
00074 finalize();
00075
00076 delete d;
00077 }
00078
00079 bool KSaveFile::open(OpenMode flags)
00080 {
00081 if ( d->realFileName.isNull() ) {
00082 d->error=QFile::OpenError;
00083 d->errorString=i18n("No target filename has been given.");
00084 return false;
00085 }
00086
00087 if ( !d->tempFileName.isNull() ) {
00088 #if 0 // do not set an error here, this open() fails, but the file itself is without errors
00089 d->error=QFile::OpenError;
00090 d->errorString=i18n("Already opened.");
00091 #endif
00092 return false;
00093 }
00094
00095
00096
00097
00098 if (!KStandardDirs::checkAccess(d->realFileName, W_OK)) {
00099 d->error=QFile::PermissionsError;
00100 d->errorString=i18n("Insufficient permissions in target directory.");
00101 return false;
00102 }
00103
00104
00105 QTemporaryFile tempFile;
00106 tempFile.setAutoRemove(false);
00107 tempFile.setFileTemplate(d->realFileName + "XXXXXX.new");
00108 if (!tempFile.open()) {
00109 d->error=QFile::OpenError;
00110 d->errorString=i18n("Unable to open temporary file.");
00111 return false;
00112 }
00113
00114
00115
00116
00117
00118 QFileInfo fi ( d->realFileName );
00119 if (fi.exists()) {
00120
00121 if (!fchown(tempFile.handle(), fi.ownerId(), fi.groupId()))
00122 tempFile.setPermissions(fi.permissions());
00123 }
00124 else {
00125 mode_t umsk = KGlobal::umask();
00126 fchmod(tempFile.handle(), 0666&(~umsk));
00127 }
00128
00129
00130 QFile::setFileName(tempFile.fileName());
00131 if (!QFile::open(flags)) {
00132 tempFile.setAutoRemove(true);
00133 return false;
00134 }
00135
00136 d->tempFileName = tempFile.fileName();
00137 d->error=QFile::NoError;
00138 d->errorString.clear();
00139 return true;
00140 }
00141
00142 void KSaveFile::setFileName(const QString &filename)
00143 {
00144 d->realFileName = filename;
00145
00146
00147 if ( QDir::isRelativePath( filename ) ) {
00148 d->realFileName = QDir::current().absoluteFilePath( filename );
00149 }
00150
00151
00152 d->realFileName = KStandardDirs::realFilePath( d->realFileName );
00153
00154 #ifdef Q_WS_WIN
00155 d->realFileName.replace(QString::fromLatin1("//"), QString::fromLatin1("/"));
00156 #endif
00157 return;
00158 }
00159
00160 QFile::FileError KSaveFile::error() const
00161 {
00162 if ( d->error != QFile::NoError ) {
00163 return d->error;
00164 } else {
00165 return QFile::error();
00166 }
00167 }
00168
00169 QString KSaveFile::errorString() const
00170 {
00171 if ( !d->errorString.isEmpty() ) {
00172 return d->errorString;
00173 } else {
00174 return QFile::errorString();
00175 }
00176 }
00177
00178 QString KSaveFile::fileName() const
00179 {
00180 return d->realFileName;
00181 }
00182
00183 void KSaveFile::abort()
00184 {
00185 if ( d->stream ) {
00186 fclose(d->stream);
00187 d->stream = 0;
00188 }
00189
00190 close();
00191 QFile::remove(d->tempFileName);
00192 d->wasFinalized = true;
00193 }
00194
00195 bool KSaveFile::finalize()
00196 {
00197 bool success = false;
00198
00199 if ( !d->wasFinalized ) {
00200 if ( d->stream ) {
00201 fclose(d->stream);
00202 d->stream = 0;
00203 }
00204 close();
00205
00206 if( error() != NoError ) {
00207 QFile::remove(d->tempFileName);
00208 }
00209
00210
00211
00212
00213
00214 else if (0 == KDE_rename(QFile::encodeName(d->tempFileName),
00215 QFile::encodeName(d->realFileName))) {
00216 d->error=QFile::NoError;
00217 d->errorString.clear();
00218 success = true;
00219 } else {
00220 d->error=QFile::OpenError;
00221 d->errorString=i18n("Error during rename.");
00222 QFile::remove(d->tempFileName);
00223 }
00224
00225 d->wasFinalized = true;
00226 }
00227
00228 return success;
00229 }
00230
00231 bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir )
00232 {
00233
00234
00235
00236
00237 KConfigGroup g(KGlobal::config(), "Backups");
00238 QString type = g.readEntry( "Type", "simple" );
00239 QString extension = g.readEntry( "Extension", "~" );
00240 QString message = g.readEntry( "Message", "Automated KDE Commit" );
00241 int maxnum = g.readEntry( "MaxBackups", 10 );
00242 if ( type.toLower() == "numbered" ) {
00243 return( numberedBackupFile( qFilename, backupDir, extension, maxnum ) );
00244 } else if ( type.toLower() == "rcs" ) {
00245 return( rcsBackupFile( qFilename, backupDir, message ) );
00246 } else {
00247 return( simpleBackupFile( qFilename, backupDir, extension ) );
00248 }
00249 }
00250
00251 bool KSaveFile::simpleBackupFile( const QString& qFilename,
00252 const QString& backupDir,
00253 const QString& backupExtension )
00254 {
00255 QString backupFileName = qFilename + backupExtension;
00256
00257 if ( !backupDir.isEmpty() ) {
00258 QFileInfo fileInfo ( qFilename );
00259 backupFileName = backupDir + '/' + fileInfo.fileName() + backupExtension;
00260 }
00261
00262
00263 QFile::remove(backupFileName);
00264 return QFile::copy(qFilename, backupFileName);
00265 }
00266
00267 bool KSaveFile::rcsBackupFile( const QString& qFilename,
00268 const QString& backupDir,
00269 const QString& backupMessage )
00270 {
00271 QFileInfo fileInfo ( qFilename );
00272
00273 QString qBackupFilename;
00274 if ( backupDir.isEmpty() ) {
00275 qBackupFilename = qFilename;
00276 } else {
00277 qBackupFilename = backupDir + fileInfo.fileName();
00278 }
00279 qBackupFilename += QString::fromLatin1( ",v" );
00280
00281
00282
00283
00284 if ( !backupDir.isEmpty() )
00285 {
00286 if ( !QFile::copy(qFilename, backupDir + fileInfo.fileName()) ) {
00287 return false;
00288 }
00289 fileInfo.setFile(backupDir + '/' + fileInfo.fileName());
00290 }
00291
00292 QString cipath = KStandardDirs::findExe("ci");
00293 QString copath = KStandardDirs::findExe("co");
00294 QString rcspath = KStandardDirs::findExe("rcs");
00295 if ( cipath.isEmpty() || copath.isEmpty() || rcspath.isEmpty() )
00296 return false;
00297
00298
00299 QProcess ci;
00300 if ( !backupDir.isEmpty() )
00301 ci.setWorkingDirectory( backupDir );
00302 ci.start( cipath, QStringList() << "-u" << fileInfo.filePath() );
00303 if ( !ci.waitForStarted() )
00304 return false;
00305 ci.write( backupMessage.toLatin1() );
00306 ci.write(".");
00307 ci.closeWriteChannel();
00308 if( !ci.waitForFinished() )
00309 return false;
00310
00311
00312 QProcess rcs;
00313 if ( !backupDir.isEmpty() )
00314 rcs.setWorkingDirectory( backupDir );
00315 rcs.start( rcspath, QStringList() << "-U" << qBackupFilename );
00316 if ( !rcs.waitForFinished() )
00317 return false;
00318
00319
00320 QProcess co;
00321 if ( !backupDir.isEmpty() )
00322 co.setWorkingDirectory( backupDir );
00323 co.start( copath, QStringList() << qBackupFilename );
00324 if ( !co.waitForFinished() )
00325 return false;
00326
00327 if ( !backupDir.isEmpty() ) {
00328 return QFile::remove( fileInfo.filePath() );
00329 } else {
00330 return true;
00331 }
00332 }
00333
00334 bool KSaveFile::numberedBackupFile( const QString& qFilename,
00335 const QString& backupDir,
00336 const QString& backupExtension,
00337 const uint maxBackups )
00338 {
00339 QFileInfo fileInfo ( qFilename );
00340
00341
00342 QString sTemplate;
00343 if ( backupDir.isEmpty() ) {
00344 sTemplate = qFilename + ".%1" + backupExtension;
00345 } else {
00346 sTemplate = backupDir + '/' + fileInfo.fileName() + ".%1" + backupExtension;
00347 }
00348
00349
00350
00351 QDir d = backupDir.isEmpty() ? fileInfo.dir() : backupDir;
00352 d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
00353 QStringList nameFilters = QStringList( fileInfo.fileName() + ".*" + backupExtension );
00354 d.setNameFilters( nameFilters );
00355 d.setSorting( QDir::Name );
00356
00357 uint maxBackupFound = 0;
00358 foreach ( const QFileInfo &fi, d.entryInfoList() ) {
00359 if ( fi.fileName().endsWith( backupExtension ) ) {
00360
00361 QString sTemp = fi.fileName();
00362 sTemp.truncate( fi.fileName().length()-backupExtension.length() );
00363
00364 int idex = sTemp.lastIndexOf( '.' );
00365 if ( idex > 0 ) {
00366 bool ok;
00367 uint num = sTemp.mid( idex+1 ).toUInt( &ok );
00368 if ( ok ) {
00369 if ( num >= maxBackups ) {
00370 QFile::remove( fi.filePath() );
00371 } else {
00372 maxBackupFound = qMax( maxBackupFound, num );
00373 }
00374 }
00375 }
00376 }
00377 }
00378
00379
00380 QString to=sTemplate.arg( maxBackupFound+1 );
00381 for ( int i=maxBackupFound; i>0; i-- ) {
00382 QString from = sTemplate.arg( i );
00383
00384 QFile::rename( from, to );
00385 to = from;
00386 }
00387
00388
00389
00390 return QFile::copy(qFilename, sTemplate.arg(1));
00391 }
00392