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
00031 #include <kconfig.h>
00032 #include <kde_file.h>
00033 #include <klocale.h>
00034 #include <kstandarddirs.h>
00035 #include <kconfiggroup.h>
00036 #include <kcomponentdata.h>
00037 #include "ktemporaryfile.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 KTemporaryFile tempFile(d->componentData);
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 return;
00154 }
00155
00156 QFile::FileError KSaveFile::error() const
00157 {
00158 if ( d->error != QFile::NoError ) {
00159 return d->error;
00160 } else {
00161 return QFile::error();
00162 }
00163 }
00164
00165 QString KSaveFile::errorString() const
00166 {
00167 if ( !d->errorString.isEmpty() ) {
00168 return d->errorString;
00169 } else {
00170 return QFile::errorString();
00171 }
00172 }
00173
00174 QString KSaveFile::fileName() const
00175 {
00176 return d->realFileName;
00177 }
00178
00179 void KSaveFile::abort()
00180 {
00181 if ( d->stream ) {
00182 fclose(d->stream);
00183 d->stream = 0;
00184 }
00185
00186 close();
00187 QFile::remove(d->tempFileName);
00188 d->wasFinalized = true;
00189 }
00190
00191 bool KSaveFile::finalize()
00192 {
00193 bool success = false;
00194
00195 if ( !d->wasFinalized ) {
00196 if ( d->stream ) {
00197 fclose(d->stream);
00198 d->stream = 0;
00199 }
00200 close();
00201
00202 if( error() != NoError ) {
00203 QFile::remove(d->tempFileName);
00204 }
00205
00206
00207
00208
00209
00210 else if (0 == KDE_rename(QFile::encodeName(d->tempFileName),
00211 QFile::encodeName(d->realFileName))) {
00212 d->error=QFile::NoError;
00213 d->errorString.clear();
00214 success = true;
00215 } else {
00216 d->error=QFile::OpenError;
00217 d->errorString=i18n("Error during rename.");
00218 QFile::remove(d->tempFileName);
00219 }
00220
00221 d->wasFinalized = true;
00222 }
00223
00224 return success;
00225 }
00226
00227 bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir )
00228 {
00229
00230
00231
00232
00233 KConfigGroup g(KGlobal::config(), "Backups");
00234 QString type = g.readEntry( "Type", "simple" );
00235 QString extension = g.readEntry( "Extension", "~" );
00236 QString message = g.readEntry( "Message", "Automated KDE Commit" );
00237 int maxnum = g.readEntry( "MaxBackups", 10 );
00238 if ( type.toLower() == "numbered" ) {
00239 return( numberedBackupFile( qFilename, backupDir, extension, maxnum ) );
00240 } else if ( type.toLower() == "rcs" ) {
00241 return( rcsBackupFile( qFilename, backupDir, message ) );
00242 } else {
00243 return( simpleBackupFile( qFilename, backupDir, extension ) );
00244 }
00245 }
00246
00247 bool KSaveFile::simpleBackupFile( const QString& qFilename,
00248 const QString& backupDir,
00249 const QString& backupExtension )
00250 {
00251 QString backupFileName = qFilename + backupExtension;
00252
00253 if ( !backupDir.isEmpty() ) {
00254 QFileInfo fileInfo ( qFilename );
00255 backupFileName = backupDir + '/' + fileInfo.fileName() + backupExtension;
00256 }
00257
00258
00259 return QFile::copy(qFilename, backupFileName);
00260 }
00261
00262 bool KSaveFile::rcsBackupFile( const QString& qFilename,
00263 const QString& backupDir,
00264 const QString& backupMessage )
00265 {
00266 QFileInfo fileInfo ( qFilename );
00267
00268 QString qBackupFilename;
00269 if ( backupDir.isEmpty() ) {
00270 qBackupFilename = qFilename;
00271 } else {
00272 qBackupFilename = backupDir + fileInfo.fileName();
00273 }
00274 qBackupFilename += QString::fromLatin1( ",v" );
00275
00276
00277
00278
00279 if ( !backupDir.isEmpty() )
00280 {
00281 if ( !QFile::copy(qFilename, backupDir + fileInfo.fileName()) ) {
00282 return false;
00283 }
00284 fileInfo.setFile(backupDir + '/' + fileInfo.fileName());
00285 }
00286
00287 QString cipath = KStandardDirs::findExe("ci");
00288 QString copath = KStandardDirs::findExe("co");
00289 QString rcspath = KStandardDirs::findExe("rcs");
00290 if ( cipath.isEmpty() || copath.isEmpty() || rcspath.isEmpty() )
00291 return false;
00292
00293
00294 QProcess ci;
00295 if ( !backupDir.isEmpty() )
00296 ci.setWorkingDirectory( backupDir );
00297 ci.start( cipath, QStringList() << "-u" << fileInfo.filePath() );
00298 if ( !ci.waitForStarted() )
00299 return false;
00300 ci.write( backupMessage.toLatin1() );
00301 ci.write(".");
00302 ci.closeWriteChannel();
00303 if( !ci.waitForFinished() )
00304 return false;
00305
00306
00307 QProcess rcs;
00308 if ( !backupDir.isEmpty() )
00309 rcs.setWorkingDirectory( backupDir );
00310 rcs.start( rcspath, QStringList() << "-U" << qBackupFilename );
00311 if ( !rcs.waitForFinished() )
00312 return false;
00313
00314
00315 QProcess co;
00316 if ( !backupDir.isEmpty() )
00317 co.setWorkingDirectory( backupDir );
00318 co.start( copath, QStringList() << qBackupFilename );
00319 if ( !co.waitForFinished() )
00320 return false;
00321
00322 if ( !backupDir.isEmpty() ) {
00323 return QFile::remove( fileInfo.filePath() );
00324 } else {
00325 return true;
00326 }
00327 }
00328
00329 bool KSaveFile::numberedBackupFile( const QString& qFilename,
00330 const QString& backupDir,
00331 const QString& backupExtension,
00332 const uint maxBackups )
00333 {
00334 QFileInfo fileInfo ( qFilename );
00335
00336
00337 QString sTemplate;
00338 if ( backupDir.isEmpty() ) {
00339 sTemplate = qFilename + ".%1" + backupExtension;
00340 } else {
00341 sTemplate = backupDir + '/' + fileInfo.fileName() + ".%1" + backupExtension;
00342 }
00343
00344
00345
00346 QDir d = backupDir.isEmpty() ? fileInfo.dir() : backupDir;
00347 d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
00348 QStringList nameFilters = QStringList( fileInfo.fileName() + ".*" + backupExtension );
00349 d.setNameFilters( nameFilters );
00350 d.setSorting( QDir::Name );
00351
00352 uint maxBackupFound = 0;
00353 foreach ( const QFileInfo &fi, d.entryInfoList() ) {
00354 if ( fi.fileName().endsWith( backupExtension ) ) {
00355
00356 QString sTemp = fi.fileName();
00357 sTemp.truncate( fi.fileName().length()-backupExtension.length() );
00358
00359 int idex = sTemp.lastIndexOf( '.' );
00360 if ( idex > 0 ) {
00361 bool ok;
00362 uint num = sTemp.mid( idex+1 ).toUInt( &ok );
00363 if ( ok ) {
00364 if ( num >= maxBackups ) {
00365 QFile::remove( fi.filePath() );
00366 } else {
00367 maxBackupFound = qMax( maxBackupFound, num );
00368 }
00369 }
00370 }
00371 }
00372 }
00373
00374
00375 QString to=sTemplate.arg( maxBackupFound+1 );
00376 for ( int i=maxBackupFound; i>0; i-- ) {
00377 QString from = sTemplate.arg( i );
00378
00379 QFile::rename( from, to );
00380 to = from;
00381 }
00382
00383
00384
00385 return QFile::copy(qFilename, sTemplate.arg(1));
00386 }
00387