summaryrefslogtreecommitdiffstats
path: root/kdecore/ksavefile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore/ksavefile.cpp')
-rw-r--r--kdecore/ksavefile.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/kdecore/ksavefile.cpp b/kdecore/ksavefile.cpp
new file mode 100644
index 000000000..35ec51da1
--- /dev/null
+++ b/kdecore/ksavefile.cpp
@@ -0,0 +1,230 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_TEST
+#include <test.h>
+#endif
+
+#include <qdatetime.h>
+#include <qdir.h>
+
+#include <kde_file.h>
+#include "kapplication.h"
+#include "ksavefile.h"
+#include "kstandarddirs.h"
+
+KSaveFile::KSaveFile(const QString &filename, int mode)
+ : mTempFile(true)
+{
+ // follow symbolic link, if any
+ QString real_filename = KStandardDirs::realFilePath(filename);
+
+ // we only check here if the directory can be written to
+ // the actual filename isn't written to, but replaced later
+ // with the contents of our tempfile
+ if (!checkAccess(real_filename, W_OK))
+ {
+ mTempFile.setError(EACCES);
+ return;
+ }
+
+ if (mTempFile.create(real_filename, QString::fromLatin1(".new"), mode))
+ {
+ mFileName = real_filename; // Set filename upon success
+
+ // if we're overwriting an existing file, ensure temp file's
+ // permissions are the same as existing file so the existing
+ // file's permissions are preserved
+ KDE_struct_stat stat_buf;
+ if (KDE_stat(QFile::encodeName(real_filename), &stat_buf)==0)
+ {
+ // But only if we own the existing file
+ if (stat_buf.st_uid == getuid())
+ {
+ bool changePermission = true;
+ if (stat_buf.st_gid != getgid())
+ {
+ if (fchown(mTempFile.handle(), (uid_t) -1, stat_buf.st_gid) != 0)
+ {
+ // Use standard permission if we can't set the group
+ changePermission = false;
+ }
+ }
+ if (changePermission)
+ fchmod(mTempFile.handle(), stat_buf.st_mode);
+ }
+ }
+ }
+}
+
+KSaveFile::~KSaveFile()
+{
+ if (mTempFile.bOpen)
+ close(); // Close if we were still open
+}
+
+QString
+KSaveFile::name() const
+{
+ return mFileName;
+}
+
+void
+KSaveFile::abort()
+{
+ mTempFile.close();
+ mTempFile.unlink();
+}
+
+bool
+KSaveFile::close()
+{
+ if (mTempFile.name().isEmpty() || mTempFile.handle()==-1)
+ return false; // Save was aborted already
+ if (!mTempFile.sync())
+ {
+ abort();
+ return false;
+ }
+ if (mTempFile.close())
+ {
+ if (0==KDE_rename(QFile::encodeName(mTempFile.name()), QFile::encodeName(mFileName)))
+ return true; // Success!
+ mTempFile.setError(errno);
+ }
+ // Something went wrong, make sure to delete the interim file.
+ mTempFile.unlink();
+ return false;
+}
+
+static int
+write_all(int fd, const char *buf, size_t len)
+{
+ while (len > 0)
+ {
+ int written = write(fd, buf, len);
+ if (written < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ buf += written;
+ len -= written;
+ }
+ return 0;
+}
+
+bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir,
+ const QString& backupExtension)
+{
+ QCString cFilename = QFile::encodeName(qFilename);
+ const char *filename = cFilename.data();
+
+ int fd = KDE_open( filename, O_RDONLY );
+ if (fd < 0)
+ return false;
+
+ KDE_struct_stat buff;
+ if ( KDE_fstat( fd, &buff) < 0 )
+ {
+ ::close( fd );
+ return false;
+ }
+
+ QCString cBackup;
+ if ( backupDir.isEmpty() )
+ cBackup = cFilename;
+ else
+ {
+ QCString nameOnly;
+ int slash = cFilename.findRev('/');
+ if (slash < 0)
+ nameOnly = cFilename;
+ else
+ nameOnly = cFilename.mid(slash + 1);
+ cBackup = QFile::encodeName(backupDir);
+ if ( backupDir[backupDir.length()-1] != '/' )
+ cBackup += '/';
+ cBackup += nameOnly;
+ }
+ cBackup += QFile::encodeName(backupExtension);
+ const char *backup = cBackup.data();
+ int permissions = buff.st_mode & 07777;
+
+ if ( KDE_stat( backup, &buff) == 0)
+ {
+ if ( unlink( backup ) != 0 )
+ {
+ ::close(fd);
+ return false;
+ }
+ }
+
+ mode_t old_umask = umask(0);
+ int fd2 = KDE_open( backup, O_WRONLY | O_CREAT | O_EXCL, permissions | S_IWUSR);
+ umask(old_umask);
+
+ if ( fd2 < 0 )
+ {
+ ::close(fd);
+ return false;
+ }
+
+ char buffer[ 32*1024 ];
+
+ while( 1 )
+ {
+ int n = ::read( fd, buffer, 32*1024 );
+ if (n == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ ::close(fd);
+ ::close(fd2);
+ return false;
+ }
+ if (n == 0)
+ break; // Finished
+
+ if (write_all( fd2, buffer, n))
+ {
+ ::close(fd);
+ ::close(fd2);
+ return false;
+ }
+ }
+
+ ::close( fd );
+
+ if (::close(fd2))
+ return false;
+ return true;
+}