30 #include <QTemporaryFile>
43 class KSaveFile::Private
49 QFile::FileError
error;
86 d->needFinalize =
false;
87 if ( d->realFileName.isNull() ) {
88 d->error=QFile::OpenError;
89 d->errorString=
i18n(
"No target filename has been given.");
93 if ( !d->tempFileName.isNull() ) {
94 #if 0 // do not set an error here, this open() fails, but the file itself is without errors
95 d->error=QFile::OpenError;
96 d->errorString=
i18n(
"Already opened.");
103 tempFile.setAutoRemove(
false);
104 tempFile.setFileTemplate(d->realFileName + QLatin1String(
"XXXXXX.new"));
105 if (!tempFile.open()) {
107 if (d->directWriteFallback && errno == EACCES) {
108 QFile::setFileName(d->realFileName);
110 d->tempFileName.clear();
112 d->needFinalize =
true;
121 const QFileInfo fileInfo(d->realFileName);
122 QDir parentDir = fileInfo.dir();
123 if (!QFileInfo(parentDir.absolutePath()).isWritable()) {
124 d->error=QFile::PermissionsError;
125 d->errorString=
i18n(
"Insufficient permissions in target directory.");
128 d->error=QFile::OpenError;
129 d->errorString=
i18n(
"Unable to open temporary file. Error was: %1.", tempFile.error());
137 QFileInfo fi ( d->realFileName );
140 if (fchown(tempFile.handle(), fi.ownerId(), fi.groupId())) {
142 fchown(tempFile.handle(), -1, fi.groupId());
145 tempFile.setPermissions(fi.permissions());
149 fchmod(tempFile.handle(), 0666&(~umsk));
153 QFile::setFileName(tempFile.fileName());
155 tempFile.setAutoRemove(
true);
159 d->tempFileName = tempFile.fileName();
161 d->errorString.clear();
162 d->needFinalize =
true;
168 d->realFileName = filename;
171 if ( QDir::isRelativePath( filename ) ) {
172 d->realFileName = QDir::current().absoluteFilePath( filename );
186 return QFile::error();
192 if ( !d->errorString.isEmpty() ) {
193 return d->errorString;
195 return QFile::errorString();
201 return d->realFileName;
207 if (!d->tempFileName.isEmpty()) {
208 QFile::remove(d->tempFileName);
209 d->needFinalize =
false;
213 #ifdef HAVE_FDATASYNC
214 # define FDATASYNC fdatasync
216 # define FDATASYNC fsync
221 if (!d->needFinalize) {
225 bool success =
false;
227 static int extraSync = -1;
229 extraSync = getenv(
"KDE_EXTRA_FSYNC") != 0 ? 1 : 0;
235 if (errno != EINTR) {
236 d->error = QFile::WriteError;
237 d->errorString =
i18n(
"Synchronization to disk failed");
247 if (!d->tempFileName.isEmpty()) {
249 QFile::remove(d->tempFileName);
256 else if (0 ==
KDE::rename(d->tempFileName,d->realFileName)) {
258 d->errorString.clear();
261 d->error=QFile::OpenError;
262 d->errorString=
i18n(
"Error during rename.");
263 QFile::remove(d->tempFileName);
268 d->needFinalize =
false;
277 d->directWriteFallback = enabled;
282 return d->directWriteFallback;
295 int maxnum = g.
readEntry(
"MaxBackups", 10 );
296 if ( type.toLower() == QLatin1String(
"numbered") ) {
298 }
else if ( type.toLower() == QLatin1String(
"rcs") ) {
307 const QString& backupExtension )
309 QString backupFileName = qFilename + backupExtension;
311 if ( !backupDir.isEmpty() ) {
312 QFileInfo fileInfo ( qFilename );
313 backupFileName = backupDir + QLatin1Char(
'/') + fileInfo.fileName() + backupExtension;
317 QFile::remove(backupFileName);
318 return QFile::copy(qFilename, backupFileName);
325 QFileInfo fileInfo ( qFilename );
328 if ( backupDir.isEmpty() ) {
329 qBackupFilename = qFilename;
331 qBackupFilename = backupDir + fileInfo.fileName();
333 qBackupFilename += QString::fromLatin1(
",v" );
338 if ( !backupDir.isEmpty() )
340 if ( !QFile::copy(qFilename, backupDir + fileInfo.fileName()) ) {
343 fileInfo.setFile(backupDir + QLatin1Char(
'/') + fileInfo.fileName());
349 if ( cipath.isEmpty() || copath.isEmpty() || rcspath.isEmpty() )
354 if ( !backupDir.isEmpty() )
355 ci.setWorkingDirectory( backupDir );
356 ci.start( cipath,
QStringList() << QString::fromLatin1(
"-u") << fileInfo.filePath() );
357 if ( !ci.waitForStarted() )
359 ci.write( backupMessage.toLatin1() );
361 ci.closeWriteChannel();
362 if( !ci.waitForFinished() )
367 if ( !backupDir.isEmpty() )
368 rcs.setWorkingDirectory( backupDir );
369 rcs.start( rcspath,
QStringList() << QString::fromLatin1(
"-U") << qBackupFilename );
370 if ( !rcs.waitForFinished() )
375 if ( !backupDir.isEmpty() )
376 co.setWorkingDirectory( backupDir );
377 co.start( copath,
QStringList() << qBackupFilename );
378 if ( !co.waitForFinished() )
381 if ( !backupDir.isEmpty() ) {
382 return QFile::remove( fileInfo.filePath() );
390 const QString& backupExtension,
391 const uint maxBackups )
393 QFileInfo fileInfo ( qFilename );
397 if ( backupDir.isEmpty() ) {
398 sTemplate = qFilename + QLatin1String(
".%1") + backupExtension;
400 sTemplate = backupDir + QLatin1Char(
'/') + fileInfo.fileName() + QLatin1String(
".%1") + backupExtension;
405 QDir d = backupDir.isEmpty() ? fileInfo.dir() : backupDir;
406 d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
407 const QStringList nameFilters =
QStringList( fileInfo.fileName() + QLatin1String(
".*") + backupExtension );
408 d.setNameFilters( nameFilters );
409 d.setSorting( QDir::Name );
411 uint maxBackupFound = 0;
412 foreach (
const QFileInfo &fi, d.entryInfoList() ) {
413 if ( fi.fileName().endsWith( backupExtension ) ) {
416 sTemp.truncate( fi.fileName().length()-backupExtension.length() );
418 int idex = sTemp.lastIndexOf( QLatin1Char(
'.') );
421 uint num = sTemp.mid( idex+1 ).toUInt( &ok );
423 if ( num >= maxBackups ) {
424 QFile::remove( fi.filePath() );
426 maxBackupFound = qMax( maxBackupFound, num );
434 QString to=sTemplate.arg( maxBackupFound+1 );
435 for (
int i=maxBackupFound; i>0; i-- ) {
436 QString from = sTemplate.arg( i );
444 return QFile::copy(qFilename, sTemplate.arg(1));
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Display a long message of a certain type.
QString i18n(const char *text)
Returns a localized version of a string.
void setDirectWriteFallback(bool enabled)
Allows writing over the existing file if necessary.
virtual ~KSaveFile()
Destructor.
QFile::FileError error() const
Returns the last error that occurred.
static QString realFilePath(const QString &filename)
Expands all symbolic links and resolves references to '/.
bool directWriteFallback() const
Returns true if the fallback solution for saving files in read-only directories is enabled...
virtual bool open(OpenMode flags=QIODevice::ReadWrite)
Open the save file.
int rename(const QString &in, const QString &out)
void abort()
Discard changes without affecting the target file.
KSaveFile()
Default constructor.
KSharedConfigPtr config()
Returns the general config object.
int open(const QString &pathname, int flags, mode_t mode)
QString fileName() const
Returns the name of the target file.
QString errorString() const
Returns a human-readable description of the last error.
mode_t umask()
Returns the umask of the process.
bool finalize()
Finalize changes to the file.
A class for one specific group in a KConfig object.
static bool rcsBackupFile(const QString &filename, const QString &backupDir=QString(), const QString &backupMessage=QString())
Static method to create an rcs backup file for a given filename.
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
Finds the executable in the system path.
void setFileName(const QString &filename)
Set the target filename for the save file.
static bool numberedBackupFile(const QString &filename, const QString &backupDir=QString(), const QString &backupExtension=QString::fromLatin1("~"), const uint maxBackups=10)
Static method to create a backup file for a given filename.
static bool backupFile(const QString &filename, const QString &backupDir=QString())
Static method to create a backup file before saving.
static bool simpleBackupFile(const QString &filename, const QString &backupDir=QString(), const QString &backupExtension=QLatin1String("~"))
Static method to create a backup file for a given filename.
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.