File indexing completed on 2024-04-21 14:55:41

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (c) 2003 Joseph Wenninger <jowenn@kde.org>
0004  *
0005  *  This library is free software; you can redistribute it and/or
0006  *  modify it under the terms of the GNU Library General Public
0007  *  License version 2 as published by the Free Software Foundation.
0008  *
0009  *  This library is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  *  Library General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU Library General Public License
0015  *  along with this library; see the file COPYING.LIB.  If not, write to
0016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  *  Boston, MA 02110-1301, USA.
0018  **/
0019 
0020 #include "ktempdir.h"
0021 #include <config-kdelibs4support.h>
0022 #include <sys/types.h>
0023 
0024 #if HAVE_SYS_STAT_H
0025 #include <sys/stat.h>
0026 #endif
0027 
0028 #include <fcntl.h>
0029 #include <stdlib.h>
0030 #include <unistd.h>
0031 #include <errno.h>
0032 #include <dirent.h>
0033 
0034 #ifdef HAVE_TEST
0035 #include <test.h>
0036 #endif
0037 #if HAVE_PATHS_H
0038 #include <paths.h>
0039 #endif
0040 
0041 #include <QDir>
0042 #include <QDebug>
0043 #include <qtemporarydir.h>
0044 
0045 #include <QCoreApplication>
0046 #include <QFileInfo>
0047 
0048 #ifdef Q_OS_UNIX
0049 static int s_umask;
0050 
0051 // Read umask before any threads are created to avoid race conditions
0052 static int kStoreUmask()
0053 {
0054     mode_t tmp = 0;
0055     s_umask = umask(tmp);
0056     return umask(s_umask);
0057 }
0058 
0059 Q_CONSTRUCTOR_FUNCTION(kStoreUmask)
0060 #elif defined(Q_OS_WIN)
0061 #include <shellapi.h>
0062 #endif
0063 
0064 
0065 class Q_DECL_HIDDEN KTempDir::Private
0066 {
0067 public:
0068     int error;
0069     QString tmpName;
0070     bool exists;
0071     bool autoRemove;
0072 
0073     Private()
0074     {
0075         autoRemove = true;
0076         exists = false;
0077         error = 0;
0078     }
0079 };
0080 
0081 KTempDir::KTempDir(const QString &directoryPrefix, int mode) : d(new Private)
0082 {
0083     (void) create(directoryPrefix.isEmpty() ? QDir::tempPath() + QLatin1Char('/') + QCoreApplication::applicationName() : directoryPrefix, mode);
0084 }
0085 
0086 bool KTempDir::create(const QString &directoryPrefix, int mode)
0087 {
0088     QByteArray nme = QFile::encodeName(directoryPrefix) + "XXXXXX";
0089     QTemporaryDir tempdir(nme);
0090     tempdir.setAutoRemove(false);
0091     if (!tempdir.isValid()) {
0092         qWarning() << "KTempDir: Error trying to create " << nme
0093                    << ": " << ::strerror(errno);
0094         d->tmpName.clear();
0095         return false;
0096     }
0097 
0098     // got a return value != 0
0099     QString realNameStr(tempdir.path());
0100     d->tmpName = realNameStr + QLatin1Char('/');
0101     qDebug() << "KTempDir: Temporary directory created :" << d->tmpName;
0102 #ifndef Q_OS_WIN
0103     if (chmod(QFile::encodeName(realNameStr), mode & (~s_umask)) < 0) {
0104         qWarning() << "KTempDir: Unable to change permissions on" << d->tmpName
0105                    << ":" << ::strerror(errno);
0106         d->error = errno;
0107         d->tmpName.clear();
0108         tempdir.remove(); // Cleanup created directory
0109         return false;
0110     }
0111 
0112     // Success!
0113     d->exists = true;
0114 
0115     // Set uid/gid (necessary for SUID programs)
0116     if (chown(QFile::encodeName(realNameStr), getuid(), getgid()) < 0) {
0117         // Just warn, but don't failover yet
0118         qWarning() << "KTempDir: Unable to change owner on" << d->tmpName
0119                    << ":" << ::strerror(errno);
0120     }
0121 
0122 #endif
0123     // Success!
0124     d->exists = true;
0125     return true;
0126 }
0127 
0128 KTempDir::~KTempDir()
0129 {
0130     if (d->autoRemove) {
0131         unlink();
0132     }
0133 
0134     delete d;
0135 }
0136 
0137 int KTempDir::status() const
0138 {
0139     return d->error;
0140 }
0141 
0142 QString KTempDir::name() const
0143 {
0144     return d->tmpName;
0145 }
0146 
0147 bool KTempDir::exists() const
0148 {
0149     return d->exists;
0150 }
0151 
0152 void KTempDir::setAutoRemove(bool autoRemove)
0153 {
0154     d->autoRemove = autoRemove;
0155 }
0156 
0157 bool KTempDir::autoRemove() const
0158 {
0159     return d->autoRemove;
0160 }
0161 
0162 void KTempDir::unlink()
0163 {
0164     if (!d->exists) {
0165         return;
0166     }
0167     if (KTempDir::removeDir(d->tmpName)) {
0168         d->error = 0;
0169     } else {
0170         d->error = errno;
0171     }
0172     d->exists = false;
0173 }
0174 
0175 #ifndef Q_OS_WIN
0176 // Auxiliary recursive function for removeDirs
0177 static bool rmtree(const QString &name)
0178 {
0179     if (QFileInfo(name).isDir()) {
0180         Q_FOREACH (const QFileInfo &entry, QDir(name).entryInfoList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot)) {
0181             if (! rmtree(entry.absoluteFilePath())) {
0182                 return false;
0183             }
0184         }
0185     }
0186     return remove(name.toLocal8Bit().data()) != -1;
0187 }
0188 #endif
0189 
0190 bool KTempDir::removeDir(const QString &path)
0191 {
0192     //kDebug(180) << path;
0193     if (!QFile::exists(path)) {
0194         return true;    // The goal is that there is no directory
0195     }
0196 
0197 #ifdef Q_OS_WIN
0198     QVarLengthArray<WCHAR, MAX_PATH> name;
0199     name.resize(path.length() + 2);   // double null terminated!
0200     memcpy(name.data(), path.utf16(), path.length() * sizeof(WCHAR));
0201     name[path.length()     ] = 0;
0202     name[path.length() + 1 ] = 0;
0203     if (path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\'))) {
0204         name[path.length() - 1 ] = 0;
0205     }
0206     SHFILEOPSTRUCTW fileOp;
0207     memset(&fileOp, 0, sizeof(SHFILEOPSTRUCTW));
0208     fileOp.wFunc = FO_DELETE;
0209     fileOp.pFrom = (LPCWSTR)name.constData();
0210     fileOp.fFlags = FOF_NOCONFIRMATION | FOF_SILENT;
0211 #ifdef _WIN32_WCE
0212     // FOF_NOERRORUI is not defined in wince
0213 #else
0214     fileOp.fFlags |= FOF_NOERRORUI;
0215 #endif
0216     errno = SHFileOperationW(&fileOp);
0217     return (errno == 0);
0218 #else
0219     return rmtree(path);
0220 #endif
0221 }
0222