KDECore
ktempdir.cpp
Go to the documentation of this file.
00001 /* kate: tab-indents off; replace-tabs on; tab-width 4; remove-trailing-space on; encoding utf-8;*/ 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (c) 2003 Joseph Wenninger <jowenn@kde.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License version 2 as published by the Free Software Foundation. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 **/ 00020 00021 #include "ktempdir.h" 00022 00023 #include <config.h> 00024 00025 #include <sys/types.h> 00026 00027 #ifdef HAVE_SYS_STAT_H 00028 #include <sys/stat.h> 00029 #endif 00030 00031 #include <fcntl.h> 00032 #include <stdlib.h> 00033 #include <unistd.h> 00034 #include <errno.h> 00035 #include <dirent.h> 00036 00037 #ifdef HAVE_TEST 00038 #include <test.h> 00039 #endif 00040 #ifdef HAVE_PATHS_H 00041 #include <paths.h> 00042 #endif 00043 00044 #include <QtCore/QDir> 00045 00046 #include "kglobal.h" 00047 #include "krandom.h" 00048 #include "kcomponentdata.h" 00049 #include "kstandarddirs.h" 00050 #include <kdebug.h> 00051 #include "kde_file.h" 00052 00053 #ifdef Q_WS_WIN 00054 #include <QtCore/QVarLengthArray> 00055 #include <windows.h> 00056 #include <shellapi.h> 00057 extern QString mkdtemp_QString (const QString &_template); 00058 #endif 00059 00060 #ifdef _WIN32_WCE 00061 #include <shellapi.h> 00062 #endif 00063 00064 class KTempDir::Private 00065 { 00066 public: 00067 int error; 00068 QString tmpName; 00069 bool exists; 00070 bool autoRemove; 00071 00072 Private() 00073 { 00074 autoRemove = true; 00075 exists = false; 00076 error=0; 00077 } 00078 }; 00079 00080 KTempDir::KTempDir(const QString &directoryPrefix, int mode) : d(new Private) 00081 { 00082 (void) create( directoryPrefix.isEmpty() ? KStandardDirs::locateLocal("tmp", KGlobal::mainComponent().componentName()) : directoryPrefix , mode); 00083 } 00084 00085 bool KTempDir::create(const QString &directoryPrefix, int mode) 00086 { 00087 (void) KRandom::random(); 00088 00089 #ifdef Q_WS_WIN 00090 const QString nme = directoryPrefix + QLatin1String("XXXXXX"); 00091 const QString realName = mkdtemp_QString(nme); 00092 if(realName.isEmpty()) 00093 { 00094 kWarning(180) << "KTempDir: Error trying to create " << nme 00095 << ": " << ::strerror(errno) << endl; 00096 d->error = errno; 00097 d->tmpName.clear(); 00098 return false; 00099 } 00100 00101 // got a return value != 0 00102 d->tmpName = realName + QLatin1Char('/'); 00103 kDebug(180) << "KTempDir: Temporary directory created :" << d->tmpName 00104 << endl; 00105 mode_t umsk = KGlobal::umask(); 00106 KDE::chmod(nme, mode&(~umsk)); 00107 00108 // Success! 00109 d->exists = true; 00110 #else 00111 QByteArray nme = QFile::encodeName(directoryPrefix) + "XXXXXX"; 00112 char *realName; 00113 if((realName=mkdtemp(nme.data())) == 0) 00114 { 00115 // Recreate it for the warning, mkdtemps emptied it 00116 nme = QFile::encodeName(directoryPrefix) + "XXXXXX"; 00117 kWarning(180) << "KTempDir: Error trying to create " << nme.data() 00118 << ": " << ::strerror(errno) << endl; 00119 d->error = errno; 00120 d->tmpName.clear(); 00121 return false; 00122 } 00123 00124 // got a return value != 0 00125 QByteArray realNameStr(realName); 00126 d->tmpName = QFile::decodeName(realNameStr)+QLatin1Char('/'); 00127 kDebug(180) << "KTempDir: Temporary directory created :" << d->tmpName 00128 << endl; 00129 00130 mode_t umsk = KGlobal::umask(); 00131 if(chmod(nme, mode&(~umsk)) < 0) { 00132 kWarning(180) << "KTempDir: Unable to change permissions on" << d->tmpName 00133 << ":" << ::strerror(errno); 00134 d->error = errno; 00135 d->tmpName.clear(); 00136 (void) ::rmdir(realName); // Cleanup created directory 00137 return false; 00138 } 00139 00140 // Success! 00141 d->exists = true; 00142 00143 // Set uid/gid (necessary for SUID programs) 00144 if(chown(nme, getuid(), getgid()) < 0) { 00145 // Just warn, but don't failover yet 00146 kWarning(180) << "KTempDir: Unable to change owner on" << d->tmpName 00147 << ":" << ::strerror(errno); 00148 } 00149 00150 #endif 00151 return true; 00152 } 00153 00154 KTempDir::~KTempDir() 00155 { 00156 if (d->autoRemove) { 00157 unlink(); 00158 } 00159 00160 delete d; 00161 } 00162 00163 int KTempDir::status() const 00164 { 00165 return d->error; 00166 } 00167 00168 QString KTempDir::name() const 00169 { 00170 return d->tmpName; 00171 } 00172 00173 bool KTempDir::exists() const 00174 { 00175 return d->exists; 00176 } 00177 00178 void KTempDir::setAutoRemove(bool autoRemove) 00179 { 00180 d->autoRemove = autoRemove; 00181 } 00182 00183 bool KTempDir::autoRemove() const 00184 { 00185 return d->autoRemove; 00186 } 00187 00188 void KTempDir::unlink() 00189 { 00190 if (!d->exists) return; 00191 if (KTempDir::removeDir(d->tmpName)) 00192 d->error=0; 00193 else 00194 d->error=errno; 00195 d->exists=false; 00196 } 00197 00198 #ifndef Q_WS_WIN 00199 // Auxiliary recursive function for removeDirs 00200 static bool rmtree(const QByteArray& name) 00201 { 00202 //kDebug(180) << "Checking directory for remove" << name; 00203 KDE_struct_stat st; 00204 if ( KDE_lstat( name.data(), &st ) == -1 ) // Do not dereference symlink! 00205 return false; 00206 if ( S_ISDIR( st.st_mode ) ) 00207 { 00208 // This is a directory, so process it 00209 //kDebug(180) << "File" << name << "is DIRECTORY!"; 00210 KDE_struct_dirent* ep; 00211 DIR* dp = ::opendir( name.data() ); 00212 if ( !dp ) 00213 return false; 00214 while ( ( ep = KDE_readdir( dp ) ) ) 00215 { 00216 //kDebug(180) << "CHECKING" << name << "/" << ep->d_name; 00217 if ( !qstrcmp( ep->d_name, "." ) || !qstrcmp( ep->d_name, ".." ) ) 00218 continue; 00219 QByteArray newName( name ); 00220 newName += '/'; 00221 newName += ep->d_name; 00222 /* 00223 * Be defensive and close the directory. 00224 * 00225 * Potential problems: 00226 * - opendir/readdir/closedir is not re-entrant 00227 * - unlink and rmdir invalidates a opendir/readdir/closedir 00228 * - limited number of file descriptors for opendir/readdir/closedir 00229 */ 00230 if ( ::closedir( dp ) ) { 00231 kDebug(180) << "Error closing" << name; 00232 return false; 00233 } 00234 // Recurse! 00235 //kDebug(180) << "RECURSE: " << newName; 00236 if ( ! rmtree( newName ) ) 00237 return false; 00238 // We have to re-open the directory before continuing 00239 dp = ::opendir( name.data() ); 00240 if ( !dp ) 00241 return false; 00242 } 00243 if ( ::closedir( dp ) ) { 00244 kDebug(180) << "Error closing" << name; 00245 return false; 00246 } 00247 //kDebug(180) << "RMDIR dir " << name; 00248 return ! ::rmdir( name ); 00249 } 00250 else 00251 { 00252 // This is a non-directory file, so remove it 00253 //kDebug(180) << "KTempDir: unlinking file" << name; 00254 return ! ::unlink( name ); 00255 } 00256 } 00257 #endif 00258 00259 bool KTempDir::removeDir( const QString& path ) 00260 { 00261 //kDebug(180) << path; 00262 if ( !QFile::exists( path ) ) 00263 return true; // The goal is that there is no directory 00264 00265 #ifdef Q_WS_WIN 00266 QVarLengthArray<WCHAR, MAX_PATH> name; 00267 name.resize( path.length() + 2 ); // double null terminated! 00268 memcpy( name.data(), path.utf16(), path.length() * sizeof(WCHAR) ); 00269 name[path.length() ] = 0; 00270 name[path.length() + 1 ] = 0; 00271 if(path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\'))) 00272 name[path.length() - 1 ] = 0; 00273 SHFILEOPSTRUCTW fileOp; 00274 memset(&fileOp, 0, sizeof(SHFILEOPSTRUCTW) ); 00275 fileOp.wFunc = FO_DELETE; 00276 fileOp.pFrom = (LPCWSTR)name.constData(); 00277 fileOp.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; 00278 #ifdef _WIN32_WCE 00279 // FOF_NOERRORUI is not defined in wince 00280 #else 00281 fileOp.fFlags |= FOF_NOERRORUI; 00282 #endif 00283 errno = SHFileOperationW( &fileOp ); 00284 return (errno == 0); 00285 #else 00286 const QByteArray cstr( QFile::encodeName( path ) ); 00287 return rmtree( cstr ); 00288 #endif 00289 } 00290
KDE 4.6 API Reference