File indexing completed on 2023-10-03 03:16:30
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