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 <sys/types.h> 00023 00024 #ifdef HAVE_SYS_STAT_H 00025 #include <sys/stat.h> 00026 #endif 00027 00028 #include <unistd.h> 00029 #include <fcntl.h> 00030 00031 #ifdef HAVE_TEST 00032 #include <test.h> 00033 #endif 00034 00035 #include <qdatetime.h> 00036 #include <qdir.h> 00037 00038 #include "kapplication.h" 00039 #include "ksavefile.h" 00040 00041 KSaveFile::KSaveFile(const QString &filename, int mode) 00042 : mTempFile(true) 00043 { 00044 00045 // follow symbolic link, if any 00046 QString real_filename = filename; 00047 00048 QFileInfo file_info(real_filename); 00049 int c=0; 00050 while(file_info.isSymLink() && ++c<6) { 00051 real_filename = file_info.readLink(); 00052 file_info.setFile( real_filename ); 00053 } 00054 00055 // we only check here if the directory can be written to 00056 // the actual filename isn't written to, but replaced later 00057 // with the contents of our tempfile 00058 if (!checkAccess(real_filename, W_OK)) 00059 { 00060 mTempFile.setError(EACCES); 00061 return; 00062 } 00063 00064 if (mTempFile.create(real_filename, QString::fromLatin1(".new"), mode)) 00065 { 00066 mFileName = real_filename; // Set filename upon success 00067 00068 // if we're overwriting an existing file, ensure temp file's 00069 // permissions are the same as existing file so the existing 00070 // file's permissions are preserved 00071 struct stat stat_buf; 00072 if ((stat(QFile::encodeName(real_filename), &stat_buf)==0) 00073 && (stat_buf.st_uid == getuid()) 00074 && (stat_buf.st_gid == getgid())) 00075 { 00076 fchmod(mTempFile.handle() , stat_buf.st_mode); 00077 } 00078 } 00079 return; 00080 } 00081 00082 KSaveFile::~KSaveFile() 00083 { 00084 if (mTempFile.bOpen) 00085 close(); // Close if we were still open 00086 } 00087 00088 QString 00089 KSaveFile::name() const 00090 { 00091 return mFileName; 00092 } 00093 00094 void 00095 KSaveFile::abort() 00096 { 00097 mTempFile.unlink(); 00098 mTempFile.close(); 00099 } 00100 00101 bool 00102 KSaveFile::close() 00103 { 00104 if (mTempFile.name().isEmpty()) 00105 return false; // Save was aborted already 00106 if (!mTempFile.sync()) 00107 { 00108 abort(); 00109 return false; 00110 } 00111 if (mTempFile.close()) 00112 { 00113 QDir dir; 00114 bool result = dir.rename( mTempFile.name(), mFileName); 00115 if ( result ) 00116 { 00117 return true; // Success! 00118 } 00119 mTempFile.setError(errno); 00120 } 00121 00122 // Something went wrong, make sure to delete the interim file. 00123 mTempFile.unlink(); 00124 return false; 00125 } 00126 00127 static int 00128 write_all(int fd, const char *buf, size_t len) 00129 { 00130 while (len > 0) 00131 { 00132 int written = write(fd, buf, len); 00133 if (written < 0) 00134 { 00135 if (errno == EINTR) 00136 continue; 00137 return -1; 00138 } 00139 buf += written; 00140 len -= written; 00141 } 00142 return 0; 00143 } 00144 00145 bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir, 00146 const QString& backupExtension) 00147 { 00148 QCString cFilename = QFile::encodeName(qFilename); 00149 const char *filename = cFilename.data(); 00150 00151 int fd = open( filename, O_RDONLY); 00152 if (fd < 0) 00153 return false; 00154 00155 struct stat buff; 00156 if ( fstat( fd, &buff) < 0 ) 00157 { 00158 ::close( fd ); 00159 return false; 00160 } 00161 00162 QCString cBackup; 00163 if ( backupDir.isEmpty() ) 00164 cBackup = cFilename; 00165 else 00166 { 00167 QCString nameOnly; 00168 int slash = cFilename.findRev('/'); 00169 if (slash < 0) 00170 nameOnly = cFilename; 00171 else 00172 nameOnly = cFilename.mid(slash + 1); 00173 cBackup = QFile::encodeName(backupDir); 00174 if ( backupDir[backupDir.length()-1] != '/' ) 00175 cBackup += '/'; 00176 cBackup += nameOnly; 00177 } 00178 cBackup += QFile::encodeName(backupExtension); 00179 const char *backup = cBackup.data(); 00180 int permissions = buff.st_mode & 07777; 00181 00182 if ( stat( backup, &buff) == 0) 00183 { 00184 if ( unlink( backup ) != 0 ) 00185 { 00186 ::close(fd); 00187 return false; 00188 } 00189 } 00190 00191 mode_t old_umask = umask(0); 00192 int fd2 = open( backup, O_WRONLY | O_CREAT | O_EXCL, permissions | S_IWUSR); 00193 umask(old_umask); 00194 00195 if ( fd2 < 0 ) 00196 { 00197 ::close(fd); 00198 return false; 00199 } 00200 00201 char buffer[ 32*1024 ]; 00202 00203 while( 1 ) 00204 { 00205 int n = ::read( fd, buffer, 32*1024 ); 00206 if (n == -1) 00207 { 00208 if (errno == EINTR) 00209 continue; 00210 ::close(fd); 00211 ::close(fd2); 00212 return false; 00213 } 00214 if (n == 0) 00215 break; // Finished 00216 00217 if (write_all( fd2, buffer, n)) 00218 { 00219 ::close(fd); 00220 ::close(fd2); 00221 return false; 00222 } 00223 } 00224 00225 ::close( fd ); 00226 00227 if (::close(fd2)) 00228 return false; 00229 return true; 00230 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:11 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003