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 514742 2006-03-01 10:20:31Z goutte $
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 
00112 int
00113 KTempDir::status() const
00114 {
00115    return mError;
00116 }
00117 
00118 QString
00119 KTempDir::name() const
00120 {
00121    return mTmpName;
00122 }
00123 
00124 bool
00125 KTempDir::existing() const
00126 {
00127    return bExisting;
00128 }
00129 
00130 QDir *
00131 KTempDir::qDir()
00132 {
00133    if (bExisting) return new QDir(mTmpName);
00134    return 0;
00135 }
00136 
00137 void
00138 KTempDir::unlink()
00139 {
00140    if (!bExisting) return;
00141    if (KTempDir::removeDir(mTmpName))
00142       mError=0;
00143    else
00144       mError=errno;
00145    bExisting=false;
00146 }
00147 
00148 // Auxiliary recursive function for removeDirs
00149 static bool
00150 rmtree(const QCString& name)
00151 {
00152     kdDebug() << "Checking directory for remove " << name << endl;
00153     KDE_struct_stat st;
00154     if ( KDE_lstat( name.data(), &st ) == -1 ) // Do not dereference symlink!
00155         return false;
00156     if ( S_ISDIR( st.st_mode ) )
00157     {
00158         // This is a directory, so process it
00159         kdDebug() << "File " << name << " is DIRECTORY!" << endl;
00160         KDE_struct_dirent* ep;
00161         DIR* dp = ::opendir( name.data() );
00162         if ( !dp )
00163             return false;
00164         while ( ( ep = KDE_readdir( dp ) ) )
00165         {
00166             kdDebug() << "CHECKING " << name << "/" << ep->d_name << endl;
00167             if ( !qstrcmp( ep->d_name, "." ) || !qstrcmp( ep->d_name, ".." ) )
00168                 continue;
00169             QCString newName( name );
00170             newName += "/"; // Careful: do not add '/' instead or you get problems with Qt3.
00171             newName += ep->d_name;
00172             /*
00173              * Be defensive and close the directory.
00174              *
00175              * Potential problems:
00176              * - opendir/readdir/closedir is not re-entrant
00177              * - unlink and rmdir invalidates a opendir/readdir/closedir
00178              * - limited number of file descriptors for opendir/readdir/closedir
00179              */
00180             if ( ::closedir( dp ) )
00181                 return false;
00182             // Recurse!
00183             kdDebug() << "RECURSE: " << newName << endl;
00184             if ( ! rmtree( newName ) )
00185                 return false;
00186             // We have to re-open the directory before continuing
00187             dp = ::opendir( name.data() );
00188             if ( !dp )
00189                 return false;
00190         }
00191         if ( ::closedir( dp ) )
00192             return false;
00193         kdDebug() << "RMDIR dir " << name << endl;
00194         return ! ::rmdir( name );
00195     }
00196     else
00197     {
00198          // This is a non-directory file, so remove it
00199          kdDebug() << "UNLINKING file " << name << endl;
00200          return ! ::unlink( name );
00201     }
00202 }
00203 
00204 bool
00205 KTempDir::removeDir(const QString& path)
00206 {
00207     kdDebug() << k_funcinfo << " " << path << endl;
00208     if ( !QFile::exists( path ) )
00209         return true; // The goal is that there is no directory
00210 
00211     const QCString cstr( QFile::encodeName( path ) );
00212     return rmtree( cstr );
00213 }
00214 
00215 
KDE Home | KDE Accessibility Home | Description of Access Keys