File indexing completed on 2024-05-05 16:13:51
0001 /* 0002 SPDX-FileCopyrightText: 2000-2002 Stephan Kulow <coolo@kde.org> 0003 SPDX-FileCopyrightText: 2000-2002 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2000-2002 Waldo Bastian <bastian@kde.org> 0005 SPDX-FileCopyrightText: 2006 Allan Sandfeld Jensen <sandfeld@kde.org> 0006 SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org> 0007 SPDX-FileCopyrightText: 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de> 0008 0009 SPDX-License-Identifier: LGPL-2.0-or-later 0010 */ 0011 0012 #include "file.h" 0013 0014 #include <qt_windows.h> 0015 0016 #include <QDir> 0017 #include <QDirIterator> 0018 #include <QFileInfo> 0019 0020 #include <KConfigGroup> 0021 #include <QDebug> 0022 0023 #include "kioglobal_p.h" 0024 0025 using namespace KIO; 0026 0027 static DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, 0028 LARGE_INTEGER TotalBytesTransferred, 0029 LARGE_INTEGER StreamSize, 0030 LARGE_INTEGER StreamBytesTransferred, 0031 DWORD dwStreamNumber, 0032 DWORD dwCallbackReason, 0033 HANDLE hSourceFile, 0034 HANDLE hDestinationFile, 0035 LPVOID lpData) 0036 { 0037 FileProtocol *f = reinterpret_cast<FileProtocol *>(lpData); 0038 f->processedSize(TotalBytesTransferred.QuadPart); 0039 return PROGRESS_CONTINUE; 0040 } 0041 0042 static UDSEntry createUDSEntryWin(const QFileInfo &fileInfo) 0043 { 0044 UDSEntry entry; 0045 0046 entry.fastInsert(KIO::UDSEntry::UDS_NAME, fileInfo.fileName()); 0047 if (fileInfo.isSymLink()) { 0048 entry.fastInsert(KIO::UDSEntry::UDS_TARGET_URL, fileInfo.symLinkTarget()); 0049 /* TODO - or not useful on windows? 0050 if ( details > 1 ) { 0051 // It is a link pointing to nowhere 0052 type = S_IFMT - 1; 0053 access = S_IRWXU | S_IRWXG | S_IRWXO; 0054 0055 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type ); 0056 entry.insert( KIO::UDSEntry::UDS_ACCESS, access ); 0057 entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL ); 0058 goto notype; 0059 0060 } 0061 */ 0062 } 0063 int type = S_IFREG; 0064 int access = 0; 0065 if (fileInfo.isDir()) { 0066 type = S_IFDIR; 0067 } else if (fileInfo.isSymLink()) { 0068 type = QT_STAT_LNK; 0069 } 0070 if (fileInfo.isReadable()) { 0071 access |= S_IRUSR; 0072 } 0073 if (fileInfo.isWritable()) { 0074 access |= S_IWUSR; 0075 } 0076 if (fileInfo.isExecutable()) { 0077 access |= S_IXUSR; 0078 } 0079 0080 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, type); 0081 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, access); 0082 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, fileInfo.size()); 0083 if (fileInfo.isHidden()) { 0084 entry.fastInsert(KIO::UDSEntry::UDS_HIDDEN, true); 0085 } 0086 0087 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, fileInfo.lastModified().toSecsSinceEpoch()); 0088 entry.fastInsert(KIO::UDSEntry::UDS_USER, fileInfo.owner()); 0089 entry.fastInsert(KIO::UDSEntry::UDS_GROUP, fileInfo.group()); 0090 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, fileInfo.lastRead().toSecsSinceEpoch()); 0091 entry.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, fileInfo.birthTime().toSecsSinceEpoch()); 0092 0093 return entry; 0094 } 0095 0096 void FileProtocol::copy(const QUrl &src, const QUrl &dest, int _mode, JobFlags _flags) 0097 { 0098 // qDebug() << "copy(): " << src << " -> " << dest << ", mode=" << _mode; 0099 0100 QFileInfo _src(src.toLocalFile()); 0101 QFileInfo _dest(dest.toLocalFile()); 0102 DWORD dwFlags = COPY_FILE_FAIL_IF_EXISTS; 0103 0104 if (_src == _dest) { 0105 error(KIO::ERR_IDENTICAL_FILES, _dest.filePath()); 0106 return; 0107 } 0108 0109 if (!_src.exists()) { 0110 error(KIO::ERR_DOES_NOT_EXIST, _src.filePath()); 0111 return; 0112 } 0113 0114 if (_src.isDir()) { 0115 error(KIO::ERR_IS_DIRECTORY, _src.filePath()); 0116 return; 0117 } 0118 0119 if (_dest.exists()) { 0120 if (_dest.isDir()) { 0121 error(KIO::ERR_DIR_ALREADY_EXIST, _dest.filePath()); 0122 return; 0123 } 0124 0125 if (!(_flags & KIO::Overwrite)) { 0126 error(KIO::ERR_FILE_ALREADY_EXIST, _dest.filePath()); 0127 return; 0128 } 0129 0130 dwFlags = 0; 0131 } 0132 0133 if (!QFileInfo(_dest.dir().absolutePath()).exists()) { 0134 _dest.dir().mkdir(_dest.dir().absolutePath()); 0135 } 0136 0137 if (CopyFileExW((LPCWSTR)_src.filePath().utf16(), (LPCWSTR)_dest.filePath().utf16(), CopyProgressRoutine, (LPVOID)this, FALSE, dwFlags) == 0) { 0138 DWORD dwLastErr = GetLastError(); 0139 if (dwLastErr == ERROR_FILE_NOT_FOUND) { 0140 error(KIO::ERR_DOES_NOT_EXIST, _src.filePath()); 0141 } else if (dwLastErr == ERROR_ACCESS_DENIED) { 0142 error(KIO::ERR_ACCESS_DENIED, _dest.filePath()); 0143 } else { 0144 error(KIO::ERR_CANNOT_RENAME, _src.filePath()); 0145 // qDebug() << "Copying file " << _src.filePath() << " failed (" << dwLastErr << ")"; 0146 } 0147 return; 0148 } 0149 0150 finished(); 0151 } 0152 0153 void FileProtocol::listDir(const QUrl &url) 0154 { 0155 // qDebug() << "========= LIST " << url << " ========="; 0156 0157 if (!url.isLocalFile()) { 0158 QUrl redir(url); 0159 redir.setScheme(configValue(QStringLiteral("DefaultRemoteProtocol"), QStringLiteral("smb"))); 0160 redirection(redir); 0161 // qDebug() << "redirecting to " << redir; 0162 finished(); 0163 return; 0164 } 0165 0166 QString path = url.toLocalFile(); 0167 // C: means current directory, a concept which makes no sense in a GUI 0168 // KCoreDireLister strips trailing slashes, let's put it back again here for C:/ 0169 if (path.length() == 2 && path.at(1) == QLatin1Char(':')) 0170 path += QLatin1Char('/'); 0171 const QFileInfo info(path); 0172 if (info.isFile()) { 0173 error(KIO::ERR_IS_FILE, path); 0174 return; 0175 } 0176 0177 QDir dir(path); 0178 dir.setFilter(QDir::AllEntries | QDir::Hidden); 0179 0180 if (!dir.exists()) { 0181 // qDebug() << "========= ERR_DOES_NOT_EXIST ========="; 0182 error(KIO::ERR_DOES_NOT_EXIST, path); 0183 return; 0184 } 0185 0186 if (!dir.isReadable()) { 0187 // qDebug() << "========= ERR_CANNOT_ENTER_DIRECTORY ========="; 0188 error(KIO::ERR_CANNOT_ENTER_DIRECTORY, path); 0189 return; 0190 } 0191 QDirIterator it(dir); 0192 UDSEntry entry; 0193 while (it.hasNext()) { 0194 it.next(); 0195 UDSEntry entry = createUDSEntryWin(it.fileInfo()); 0196 0197 listEntry(entry); 0198 entry.clear(); 0199 } 0200 0201 // qDebug() << "============= COMPLETED LIST ============"; 0202 0203 finished(); 0204 } 0205 0206 void FileProtocol::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags _flags) 0207 { 0208 // qDebug() << "rename(): " << src << " -> " << dest; 0209 0210 QFileInfo _src(src.toLocalFile()); 0211 QFileInfo _dest(dest.toLocalFile()); 0212 DWORD dwFlags = 0; 0213 0214 if (_src == _dest) { 0215 error(KIO::ERR_IDENTICAL_FILES, _dest.filePath()); 0216 return; 0217 } 0218 0219 if (!_src.exists()) { 0220 error(KIO::ERR_DOES_NOT_EXIST, _src.filePath()); 0221 return; 0222 } 0223 0224 if (_dest.exists()) { 0225 if (_dest.isDir()) { 0226 error(KIO::ERR_DIR_ALREADY_EXIST, _dest.filePath()); 0227 return; 0228 } 0229 0230 if (!(_flags & KIO::Overwrite)) { 0231 error(KIO::ERR_FILE_ALREADY_EXIST, _dest.filePath()); 0232 return; 0233 } 0234 0235 #ifndef _WIN32_WCE 0236 dwFlags = MOVEFILE_REPLACE_EXISTING; 0237 #endif 0238 } 0239 // To avoid error 17 - The system cannot move the file to a different disk drive. 0240 #ifndef _WIN32_WCE 0241 dwFlags |= MOVEFILE_COPY_ALLOWED; 0242 0243 if (MoveFileExW((LPCWSTR)_src.filePath().utf16(), (LPCWSTR)_dest.filePath().utf16(), dwFlags) == 0) 0244 #else 0245 if (MoveFileW((LPCWSTR)_src.filePath().utf16(), (LPCWSTR)_dest.filePath().utf16()) == 0) 0246 #endif 0247 { 0248 DWORD dwLastErr = GetLastError(); 0249 if (dwLastErr == ERROR_FILE_NOT_FOUND) { 0250 error(KIO::ERR_DOES_NOT_EXIST, _src.filePath()); 0251 } else if (dwLastErr == ERROR_ACCESS_DENIED) { 0252 error(KIO::ERR_ACCESS_DENIED, _dest.filePath()); 0253 } else { 0254 error(KIO::ERR_CANNOT_RENAME, _src.filePath()); 0255 qCDebug(KIO_FILE) << "Renaming file " << _src.filePath() << " failed (" << dwLastErr << ")"; 0256 } 0257 return; 0258 } 0259 0260 finished(); 0261 } 0262 0263 void FileProtocol::symlink(const QString &target, const QUrl &dest, KIO::JobFlags flags) 0264 { 0265 QString localDest = dest.toLocalFile(); 0266 // TODO handle overwrite, etc 0267 if (!KIOPrivate::createSymlink(target, localDest)) { 0268 error(KIO::ERR_UNKNOWN, localDest); 0269 } 0270 } 0271 0272 void FileProtocol::del(const QUrl &url, bool isfile) 0273 { 0274 QString _path(url.toLocalFile()); 0275 /***** 0276 * Delete files 0277 *****/ 0278 0279 if (isfile) { 0280 // qDebug() << "Deleting file " << _path; 0281 0282 if (DeleteFileW((LPCWSTR)_path.utf16()) == 0) { 0283 DWORD dwLastErr = GetLastError(); 0284 if (dwLastErr == ERROR_PATH_NOT_FOUND) { 0285 error(KIO::ERR_DOES_NOT_EXIST, _path); 0286 } else if (dwLastErr == ERROR_ACCESS_DENIED) { 0287 error(KIO::ERR_ACCESS_DENIED, _path); 0288 } else { 0289 error(KIO::ERR_CANNOT_DELETE, _path); 0290 // qDebug() << "Deleting file " << _path << " failed (" << dwLastErr << ")"; 0291 } 0292 } 0293 } else { 0294 // qDebug() << "Deleting directory " << _path; 0295 if (!deleteRecursive(_path)) { 0296 return; 0297 } 0298 if (RemoveDirectoryW((LPCWSTR)_path.utf16()) == 0) { 0299 DWORD dwLastErr = GetLastError(); 0300 if (dwLastErr == ERROR_FILE_NOT_FOUND) { 0301 error(KIO::ERR_DOES_NOT_EXIST, _path); 0302 } else if (dwLastErr == ERROR_ACCESS_DENIED) { 0303 error(KIO::ERR_ACCESS_DENIED, _path); 0304 } else { 0305 error(KIO::ERR_CANNOT_DELETE, _path); 0306 // qDebug() << "Deleting directory " << _path << " failed (" << dwLastErr << ")"; 0307 } 0308 } 0309 } 0310 finished(); 0311 } 0312 0313 void FileProtocol::chown(const QUrl &url, const QString &, const QString &) 0314 { 0315 error(KIO::ERR_CANNOT_CHOWN, url.toLocalFile()); 0316 } 0317 0318 void FileProtocol::stat(const QUrl &url) 0319 { 0320 if (!url.isLocalFile()) { 0321 redirect(url); 0322 return; 0323 } 0324 0325 const QString sDetails = metaData(QLatin1String("details")); 0326 int details = sDetails.isEmpty() ? 2 : sDetails.toInt(); 0327 // qDebug() << "FileProtocol::stat details=" << details; 0328 0329 const QString localFile = url.toLocalFile(); 0330 QFileInfo fileInfo(localFile); 0331 if (!fileInfo.exists()) { 0332 error(KIO::ERR_DOES_NOT_EXIST, localFile); 0333 return; 0334 } 0335 0336 UDSEntry entry = createUDSEntryWin(fileInfo); 0337 0338 statEntry(entry); 0339 0340 finished(); 0341 } 0342 0343 bool FileProtocol::privilegeOperationUnitTestMode() 0344 { 0345 return false; 0346 } 0347 0348 PrivilegeOperationReturnValue FileProtocol::execWithElevatedPrivilege(ActionType, const QVariantList &, int err) 0349 { 0350 return PrivilegeOperationReturnValue::failure(err); 0351 } 0352 PrivilegeOperationReturnValue FileProtocol::tryOpen(QFile &f, const QByteArray &, int, int, int err) 0353 { 0354 return PrivilegeOperationReturnValue::failure(err); 0355 } 0356 0357 PrivilegeOperationReturnValue FileProtocol::tryChangeFileAttr(ActionType, const QVariantList &, int err) 0358 { 0359 return PrivilegeOperationReturnValue::failure(err); 0360 } 0361 0362 int FileProtocol::setACL(const char *path, mode_t perm, bool directoryDefault) 0363 { 0364 Q_UNUSED(path); 0365 Q_UNUSED(perm); 0366 Q_UNUSED(directoryDefault); 0367 return 0; 0368 }