kdecore Library API Documentation

ksavefile.cpp

00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (c) 1999 Waldo Bastian <bastian@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include <config.h> 00021 00022 #include <stdlib.h> 00023 #include <sys/types.h> 00024 00025 #ifdef HAVE_SYS_STAT_H 00026 #include <sys/stat.h> 00027 #endif 00028 00029 #include <sys/param.h> 00030 #include <unistd.h> 00031 #include <fcntl.h> 00032 00033 #ifdef HAVE_TEST 00034 #include <test.h> 00035 #endif 00036 00037 #include <qdatetime.h> 00038 #include <qdir.h> 00039 00040 #include "kapplication.h" 00041 #include "ksavefile.h" 00042 #include "kstandarddirs.h" 00043 00044 static QString realFilePath(const QString &filename) 00045 { 00046 char realpath_buffer[MAXPATHLEN + 1]; 00047 memset(realpath_buffer, 0, MAXPATHLEN + 1); 00048 00049 /* If the path contains symlinks, get the real name */ 00050 if (realpath( QFile::encodeName(filename).data(), realpath_buffer) != 0) { 00051 // succes, use result from realpath 00052 return QFile::decodeName(realpath_buffer); 00053 } 00054 00055 return filename; 00056 } 00057 00058 00059 KSaveFile::KSaveFile(const QString &filename, int mode) 00060 : mTempFile(true) 00061 { 00062 // follow symbolic link, if any 00063 QString real_filename = realFilePath(filename); 00064 00065 // we only check here if the directory can be written to 00066 // the actual filename isn't written to, but replaced later 00067 // with the contents of our tempfile 00068 if (!checkAccess(real_filename, W_OK)) 00069 { 00070 mTempFile.setError(EACCES); 00071 return; 00072 } 00073 00074 if (mTempFile.create(real_filename, QString::fromLatin1(".new"), mode)) 00075 { 00076 mFileName = real_filename; // Set filename upon success 00077 00078 // if we're overwriting an existing file, ensure temp file's 00079 // permissions are the same as existing file so the existing 00080 // file's permissions are preserved 00081 struct stat stat_buf; 00082 if (stat(QFile::encodeName(real_filename), &stat_buf)==0) 00083 { 00084 // But only if we own the existing file 00085 if (stat_buf.st_uid == getuid()) 00086 { 00087 bool changePermission = true; 00088 if (stat_buf.st_gid != getgid()) 00089 { 00090 if (fchown(mTempFile.handle(), (uid_t) -1, stat_buf.st_gid) != 0) 00091 { 00092 // Use standard permission if we can't set the group 00093 changePermission = false; 00094 } 00095 } 00096 if (changePermission) 00097 fchmod(mTempFile.handle(), stat_buf.st_mode); 00098 } 00099 } 00100 } 00101 return; 00102 } 00103 00104 KSaveFile::~KSaveFile() 00105 { 00106 if (mTempFile.bOpen) 00107 close(); // Close if we were still open 00108 } 00109 00110 QString 00111 KSaveFile::name() const 00112 { 00113 return mFileName; 00114 } 00115 00116 void 00117 KSaveFile::abort() 00118 { 00119 mTempFile.unlink(); 00120 mTempFile.close(); 00121 } 00122 00123 bool 00124 KSaveFile::close() 00125 { 00126 if (mTempFile.name().isEmpty()) 00127 return false; // Save was aborted already 00128 if (!mTempFile.sync()) 00129 { 00130 abort(); 00131 return false; 00132 } 00133 if (mTempFile.close()) 00134 { 00135 QDir dir; 00136 bool result = dir.rename( mTempFile.name(), mFileName); 00137 if ( result ) 00138 { 00139 return true; // Success! 00140 } 00141 mTempFile.setError(errno); 00142 } 00143 00144 // Something went wrong, make sure to delete the interim file. 00145 mTempFile.unlink(); 00146 return false; 00147 } 00148 00149 static int 00150 write_all(int fd, const char *buf, size_t len) 00151 { 00152 while (len > 0) 00153 { 00154 int written = write(fd, buf, len); 00155 if (written < 0) 00156 { 00157 if (errno == EINTR) 00158 continue; 00159 return -1; 00160 } 00161 buf += written; 00162 len -= written; 00163 } 00164 return 0; 00165 } 00166 00167 bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir, 00168 const QString& backupExtension) 00169 { 00170 QCString cFilename = QFile::encodeName(qFilename); 00171 const char *filename = cFilename.data(); 00172 00173 int fd = open( filename, O_RDONLY); 00174 if (fd < 0) 00175 return false; 00176 00177 struct stat buff; 00178 if ( fstat( fd, &buff) < 0 ) 00179 { 00180 ::close( fd ); 00181 return false; 00182 } 00183 00184 QCString cBackup; 00185 if ( backupDir.isEmpty() ) 00186 cBackup = cFilename; 00187 else 00188 { 00189 QCString nameOnly; 00190 int slash = cFilename.findRev('/'); 00191 if (slash < 0) 00192 nameOnly = cFilename; 00193 else 00194 nameOnly = cFilename.mid(slash + 1); 00195 cBackup = QFile::encodeName(backupDir); 00196 if ( backupDir[backupDir.length()-1] != '/' ) 00197 cBackup += '/'; 00198 cBackup += nameOnly; 00199 } 00200 cBackup += QFile::encodeName(backupExtension); 00201 const char *backup = cBackup.data(); 00202 int permissions = buff.st_mode & 07777; 00203 00204 if ( stat( backup, &buff) == 0) 00205 { 00206 if ( unlink( backup ) != 0 ) 00207 { 00208 ::close(fd); 00209 return false; 00210 } 00211 } 00212 00213 mode_t old_umask = umask(0); 00214 int fd2 = open( backup, O_WRONLY | O_CREAT | O_EXCL, permissions | S_IWUSR); 00215 umask(old_umask); 00216 00217 if ( fd2 < 0 ) 00218 { 00219 ::close(fd); 00220 return false; 00221 } 00222 00223 char buffer[ 32*1024 ]; 00224 00225 while( 1 ) 00226 { 00227 int n = ::read( fd, buffer, 32*1024 ); 00228 if (n == -1) 00229 { 00230 if (errno == EINTR) 00231 continue; 00232 ::close(fd); 00233 ::close(fd2); 00234 return false; 00235 } 00236 if (n == 0) 00237 break; // Finished 00238 00239 if (write_all( fd2, buffer, n)) 00240 { 00241 ::close(fd); 00242 ::close(fd2); 00243 return false; 00244 } 00245 } 00246 00247 ::close( fd ); 00248 00249 if (::close(fd2)) 00250 return false; 00251 return true; 00252 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:26:09 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003