/* * * This file is part of the KDE libraries * Copyright (c) 2003 Joseph Wenninger * * $Id$ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. **/ #include #include #ifdef HAVE_SYS_STAT_H #include #endif #include #include #include #include #ifdef HAVE_TEST #include #endif #ifdef HAVE_PATHS_H #include #endif #ifndef _PATH_TMP #define _PATH_TMP "/tmp" #endif #include #include #include "tdeglobal.h" #include "tdeapplication.h" #include "kinstance.h" #include "ktempdir.h" #include "kstandarddirs.h" #include "kprocess.h" #include #include "kde_file.h" KTempDir::KTempDir(TQString directoryPrefix, int mode) { bAutoDelete = false; bExisting = false; mError=0; if (directoryPrefix.isEmpty()) { directoryPrefix = locateLocal("tmp", TDEGlobal::instance()->instanceName()); } (void) create(directoryPrefix , mode); } bool KTempDir::create(const TQString &directoryPrefix, int mode) { // make sure the random seed is randomized (void) TDEApplication::random(); TQCString nme = TQFile::encodeName(directoryPrefix) + "XXXXXX"; char *realName; if((realName=mkdtemp(nme.data())) == 0) { // Recreate it for the warning, mkdtemps emptied it TQCString nme = TQFile::encodeName(directoryPrefix) + "XXXXXX"; tqWarning("KTempDir: Error trying to create %s: %s", nme.data(), strerror(errno)); mError = errno; mTmpName = TQString::null; return false; } // got a return value != 0 TQCString realNameStr(realName); mTmpName = TQFile::decodeName(realNameStr)+"/"; kdDebug(180) << "KTempDir: Temporary directory created :" << mTmpName << endl; mode_t tmp = 0; mode_t umsk = umask(tmp); umask(umsk); chmod(nme, mode&(~umsk)); // Success! bExisting = true; // Set uid/gid (necessary for SUID programs) chown(nme, getuid(), getgid()); return true; } KTempDir::~KTempDir() { if (bAutoDelete) unlink(); // KTempDirPrivate doesn't exist, so it can't be deleted // delete d; } int KTempDir::status() const { return mError; } TQString KTempDir::name() const { return mTmpName; } bool KTempDir::existing() const { return bExisting; } TQDir * KTempDir::qDir() { if (bExisting) return new TQDir(mTmpName); return 0; } void KTempDir::unlink() { if (!bExisting) return; if (KTempDir::removeDir(mTmpName)) mError=0; else mError=errno; bExisting=false; } // Auxiliary recursive function for removeDirs static bool rmtree(const TQCString& name) { kdDebug() << "Checking directory for remove " << name << endl; KDE_struct_stat st; if ( KDE_lstat( name.data(), &st ) == -1 ) // Do not dereference symlink! return false; if ( S_ISDIR( st.st_mode ) ) { // This is a directory, so process it kdDebug() << "File " << name << " is DIRECTORY!" << endl; KDE_struct_dirent* ep; DIR* dp = ::opendir( name.data() ); if ( !dp ) return false; while ( ( ep = KDE_readdir( dp ) ) ) { kdDebug() << "CHECKING " << name << "/" << ep->d_name << endl; if ( !qstrcmp( ep->d_name, "." ) || !qstrcmp( ep->d_name, ".." ) ) continue; TQCString newName( name ); newName += "/"; // Careful: do not add '/' instead or you get problems with Qt3. newName += ep->d_name; /* * Be defensive and close the directory. * * Potential problems: * - opendir/readdir/closedir is not re-entrant * - unlink and rmdir invalidates a opendir/readdir/closedir * - limited number of file descriptors for opendir/readdir/closedir */ if ( ::closedir( dp ) ) return false; // Recurse! kdDebug() << "RECURSE: " << newName << endl; if ( ! rmtree( newName ) ) return false; // We have to re-open the directory before continuing dp = ::opendir( name.data() ); if ( !dp ) return false; } if ( ::closedir( dp ) ) return false; kdDebug() << "RMDIR dir " << name << endl; return ! ::rmdir( name ); } else { // This is a non-directory file, so remove it kdDebug() << "UNLINKING file " << name << endl; return ! ::unlink( name ); } } bool KTempDir::removeDir(const TQString& path) { kdDebug() << k_funcinfo << " " << path << endl; if ( !TQFile::exists( path ) ) return true; // The goal is that there is no directory const TQCString cstr( TQFile::encodeName( path ) ); return rmtree( cstr ); }