ktempdir.cpp
00001 /* 00002 * 00003 * This file is part of the KDE libraries 00004 * Copyright (c) 2003 Joseph Wenninger <jowenn@kde.org> 00005 * 00006 * $Id: ktempdir.cpp 532292 2006-04-21 15:19:53Z savernik $ 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License version 2 as published by the Free Software Foundation. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 **/ 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 <dirent.h> 00035 00036 #ifdef HAVE_TEST 00037 #include <test.h> 00038 #endif 00039 #ifdef HAVE_PATHS_H 00040 #include <paths.h> 00041 #endif 00042 00043 #ifndef _PATH_TMP 00044 #define _PATH_TMP "/tmp" 00045 #endif 00046 00047 #include <qdatetime.h> 00048 #include <qdir.h> 00049 00050 #include "kglobal.h" 00051 #include "kapplication.h" 00052 #include "kinstance.h" 00053 #include "ktempdir.h" 00054 #include "kstandarddirs.h" 00055 #include "kprocess.h" 00056 #include <kdebug.h> 00057 #include "kde_file.h" 00058 00059 KTempDir::KTempDir(QString directoryPrefix, int mode) 00060 { 00061 bAutoDelete = false; 00062 bExisting = false; 00063 mError=0; 00064 if (directoryPrefix.isEmpty()) 00065 { 00066 directoryPrefix = locateLocal("tmp", KGlobal::instance()->instanceName()); 00067 } 00068 (void) create(directoryPrefix , mode); 00069 } 00070 00071 bool 00072 KTempDir::create(const QString &directoryPrefix, int mode) 00073 { 00074 // make sure the random seed is randomized 00075 (void) KApplication::random(); 00076 00077 QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX"; 00078 char *realName; 00079 if((realName=mkdtemp(nme.data())) == 0) 00080 { 00081 // Recreate it for the warning, mkdtemps emptied it 00082 QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX"; 00083 qWarning("KTempDir: Error trying to create %s: %s", nme.data(), strerror(errno)); 00084 mError = errno; 00085 mTmpName = QString::null; 00086 return false; 00087 } 00088 00089 // got a return value != 0 00090 QCString realNameStr(realName); 00091 mTmpName = QFile::decodeName(realNameStr)+"/"; 00092 kdDebug(180) << "KTempDir: Temporary directory created :" << mTmpName << endl; 00093 mode_t tmp = 0; 00094 mode_t umsk = umask(tmp); 00095 umask(umsk); 00096 chmod(nme, mode&(~umsk)); 00097 00098 // Success! 00099 bExisting = true; 00100 00101 // Set uid/gid (necessary for SUID programs) 00102 chown(nme, getuid(), getgid()); 00103 return true; 00104 } 00105 00106 KTempDir::~KTempDir() 00107 { 00108 if (bAutoDelete) 00109 unlink(); 00110 00111 // KTempDirPrivate doesn't exist, so it can't be deleted 00112 // delete d; 00113 } 00114 00115 int 00116 KTempDir::status() const 00117 { 00118 return mError; 00119 } 00120 00121 QString 00122 KTempDir::name() const 00123 { 00124 return mTmpName; 00125 } 00126 00127 bool 00128 KTempDir::existing() const 00129 { 00130 return bExisting; 00131 } 00132 00133 QDir * 00134 KTempDir::qDir() 00135 { 00136 if (bExisting) return new QDir(mTmpName); 00137 return 0; 00138 } 00139 00140 void 00141 KTempDir::unlink() 00142 { 00143 if (!bExisting) return; 00144 if (KTempDir::removeDir(mTmpName)) 00145 mError=0; 00146 else 00147 mError=errno; 00148 bExisting=false; 00149 } 00150 00151 // Auxiliary recursive function for removeDirs 00152 static bool 00153 rmtree(const QCString& name) 00154 { 00155 kdDebug() << "Checking directory for remove " << name << endl; 00156 KDE_struct_stat st; 00157 if ( KDE_lstat( name.data(), &st ) == -1 ) // Do not dereference symlink! 00158 return false; 00159 if ( S_ISDIR( st.st_mode ) ) 00160 { 00161 // This is a directory, so process it 00162 kdDebug() << "File " << name << " is DIRECTORY!" << endl; 00163 KDE_struct_dirent* ep; 00164 DIR* dp = ::opendir( name.data() ); 00165 if ( !dp ) 00166 return false; 00167 while ( ( ep = KDE_readdir( dp ) ) ) 00168 { 00169 kdDebug() << "CHECKING " << name << "/" << ep->d_name << endl; 00170 if ( !qstrcmp( ep->d_name, "." ) || !qstrcmp( ep->d_name, ".." ) ) 00171 continue; 00172 QCString newName( name ); 00173 newName += "/"; // Careful: do not add '/' instead or you get problems with Qt3. 00174 newName += ep->d_name; 00175 /* 00176 * Be defensive and close the directory. 00177 * 00178 * Potential problems: 00179 * - opendir/readdir/closedir is not re-entrant 00180 * - unlink and rmdir invalidates a opendir/readdir/closedir 00181 * - limited number of file descriptors for opendir/readdir/closedir 00182 */ 00183 if ( ::closedir( dp ) ) 00184 return false; 00185 // Recurse! 00186 kdDebug() << "RECURSE: " << newName << endl; 00187 if ( ! rmtree( newName ) ) 00188 return false; 00189 // We have to re-open the directory before continuing 00190 dp = ::opendir( name.data() ); 00191 if ( !dp ) 00192 return false; 00193 } 00194 if ( ::closedir( dp ) ) 00195 return false; 00196 kdDebug() << "RMDIR dir " << name << endl; 00197 return ! ::rmdir( name ); 00198 } 00199 else 00200 { 00201 // This is a non-directory file, so remove it 00202 kdDebug() << "UNLINKING file " << name << endl; 00203 return ! ::unlink( name ); 00204 } 00205 } 00206 00207 bool 00208 KTempDir::removeDir(const QString& path) 00209 { 00210 kdDebug() << k_funcinfo << " " << path << endl; 00211 if ( !QFile::exists( path ) ) 00212 return true; // The goal is that there is no directory 00213 00214 const QCString cstr( QFile::encodeName( path ) ); 00215 return rmtree( cstr ); 00216 } 00217 00218