Index: src/ioslaves/file/file.cpp =================================================================== --- src/ioslaves/file/file.cpp +++ src/ioslaves/file/file.cpp @@ -77,6 +77,8 @@ #include #include +#include "sharefd.h" + Q_LOGGING_CATEGORY(KIO_FILE, "kf5.kio.kio_file") // Pseudo plugin class to embed meta data @@ -229,22 +231,25 @@ (setACL(_path.data(), permissions, false) == -1) || /* if not a directory, cannot set default ACLs */ (setACL(_path.data(), permissions, true) == -1 && errno != ENOTDIR)) { - - switch (errno) { - case EPERM: - case EACCES: - error(KIO::ERR_ACCESS_DENIED, path); - break; -#if defined(ENOTSUP) - case ENOTSUP: // from setACL since chmod can't return ENOTSUP - error(KIO::ERR_UNSUPPORTED_ACTION, i18n("Setting ACL for %1", path)); - break; -#endif - case ENOSPC: - error(KIO::ERR_DISK_FULL, path); - break; - default: - error(KIO::ERR_CANNOT_CHMOD, path); + if (auto err = execWithElevatedPrivilege(CHMOD, _path, permissions)) { + if (!err.wasCanceled()) { + switch (errno) { + case EPERM: + case EACCES: + error(KIO::ERR_ACCESS_DENIED, path); + break; + #if defined(ENOTSUP) + case ENOTSUP: // from setACL since chmod can't return ENOTSUP + error(KIO::ERR_UNSUPPORTED_ACTION, i18n("Setting ACL for %1", path)); + break; + #endif + case ENOSPC: + error(KIO::ERR_DISK_FULL, path); + break; + default: + error(KIO::ERR_CANNOT_CHMOD, path); + } + } } } else { finished(); @@ -260,8 +265,12 @@ utbuf.actime = statbuf.st_atime; // access time, unchanged utbuf.modtime = mtime.toTime_t(); // modification time if (::utime(QFile::encodeName(path).constData(), &utbuf) != 0) { - // TODO: errno could be EACCES, EPERM, EROFS - error(KIO::ERR_CANNOT_SETTIME, path); + if (auto err = execWithElevatedPrivilege(UTIME, path, qint64(utbuf.actime), qint64(utbuf.modtime))) { + if (!err.wasCanceled()) { + // TODO: errno could be EACCES, EPERM, EROFS + error(KIO::ERR_CANNOT_SETTIME, path); + } + } } else { finished(); } @@ -278,16 +287,31 @@ // Remove existing file or symlink, if requested (#151851) if (metaData(QStringLiteral("overwrite")) == QLatin1String("true")) { - QFile::remove(path); + if (!QFile::remove(path)) { + if (auto err = execWithElevatedPrivilege(DEL, path)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_DELETE_ORIGINAL, path); + } + return; + } + } } QT_STATBUF buff; if (QT_LSTAT(QFile::encodeName(path).constData(), &buff) == -1) { - if (!QDir().mkdir(path)) { - //TODO: add access denied & disk full (or another reasons) handling (into Qt, possibly) - error(KIO::ERR_CANNOT_MKDIR, path); - return; - } else { + bool dirCreated; + if (!(dirCreated = QDir().mkdir(path))) { + if (auto err = execWithElevatedPrivilege(MKDIR, path)) { + if (!err.wasCanceled()) { + //TODO: add access denied & disk full (or another reasons) handling (into Qt, possibly) + error(KIO::ERR_CANNOT_MKDIR, path); + } + return; + } + dirCreated = true; + } + + if (dirCreated) { if (permissions != -1) { chmod(url, permissions); } else { @@ -338,8 +362,12 @@ QFile f(path); if (!f.open(QIODevice::ReadOnly)) { - error(KIO::ERR_CANNOT_OPEN_FOR_READING, path); - return; + if (auto err = tryOpen(f, QFile::encodeName(path), O_RDONLY, S_IRUSR)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_OPEN_FOR_READING, path); + } + return; + } } #if HAVE_FADVISE @@ -614,15 +642,37 @@ } if (!f.isOpen()) { - // qDebug() << "####################### COULD NOT WRITE" << dest << "_mode=" << _mode; - // qDebug() << "QFile error==" << f.error() << "(" << f.errorString() << ")"; + int oflags = 0; + int filemode = 0; + QFile::OpenMode openMode; - if (f.error() == QFileDevice::PermissionsError) { - error(KIO::ERR_WRITE_ACCESS_DENIED, dest); + if (_flags & KIO::Resume) { + oflags = O_RDWR | O_APPEND; + openMode = QIODevice::ReadWrite | QIODevice::Append; } else { - error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest); + oflags = O_WRONLY | O_TRUNC | O_CREAT; + filemode = _mode | S_IWUSR | S_IRUSR; + openMode = QIODevice::Truncate | QIODevice::WriteOnly; + } + + if (auto err = tryOpen(f, QFile::encodeName(dest), oflags, filemode)) { + if (!err.wasCanceled()) { + // qDebug() << "####################### COULD NOT WRITE" << dest << "_mode=" << _mode; + // qDebug() << "QFile error==" << f.error() << "(" << f.errorString() << ")"; + + if (f.error() == QFileDevice::PermissionsError) { + error(KIO::ERR_WRITE_ACCESS_DENIED, dest); + } else { + error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest); + } + } + return; + } else { + if (oflags & O_CREAT) { + execWithElevatedPrivilege(CHOWN, dest, getuid(), getgid()); + f.setPermissions(modeToQFilePermissions(filemode)); + } } - return; } } @@ -676,24 +726,31 @@ //QFile::rename() never overwrites the destination file unlike ::remove, //so we must remove it manually first if (_flags & KIO::Overwrite) { - QFile::remove(dest_orig); + if (!QFile::remove(dest_orig)) { + execWithElevatedPrivilege(DEL, dest_orig); + } } if (!QFile::rename(dest, dest_orig)) { - qCWarning(KIO_FILE) << " Couldn't rename " << dest << " to " << dest_orig; - error(KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig); - return; + if (auto err = execWithElevatedPrivilege(RENAME, dest, dest_orig)) { + if (!err.wasCanceled()) { + qCWarning(KIO_FILE) << " Couldn't rename " << dest << " to " << dest_orig; + error(KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig); + } + return; + } } org::kde::KDirNotify::emitFileRenamed(QUrl::fromLocalFile(dest), QUrl::fromLocalFile(dest_orig)); } // set final permissions if (_mode != -1 && !(_flags & KIO::Resume)) { if (!QFile::setPermissions(dest_orig, modeToQFilePermissions(_mode))) { // couldn't chmod. Eat the error if the filesystem apparently doesn't support it. - KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(dest_orig); - if (mp && mp->testFileSystemFlag(KMountPoint::SupportsChmod)) { - warning(i18n("Could not change permissions for\n%1", dest_orig)); + if (auto err = execWithElevatedPrivilege(CHMOD, dest_orig, _mode)) { + if (!err.wasCanceled()) { + warning(i18n("Could not change permissions for\n%1", dest_orig)); + } } } } @@ -718,7 +775,9 @@ struct utimbuf utbuf; utbuf.actime = dest_statbuf.st_atime; utbuf.modtime = dt.toTime_t(); - utime(QFile::encodeName(dest_orig).constData(), &utbuf); + if (utime(QFile::encodeName(dest_orig).constData(), &utbuf) != 0) { + execWithElevatedPrivilege(UTIME, dest_orig, qint64(utbuf.actime), qint64(utbuf.modtime)); + } #endif } } @@ -1330,17 +1389,25 @@ } else { //qDebug() << "QFile::remove" << itemPath; if (!QFile::remove(itemPath)) { - error(KIO::ERR_CANNOT_DELETE, itemPath); - return false; + if (auto err = execWithElevatedPrivilege(DEL, itemPath)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_DELETE, itemPath); + } + return false; + } } } } QDir dir; Q_FOREACH (const QString &itemPath, dirsToDelete) { //qDebug() << "QDir::rmdir" << itemPath; if (!dir.rmdir(itemPath)) { - error(KIO::ERR_CANNOT_DELETE, itemPath); - return false; + if (auto err = execWithElevatedPrivilege(RMDIR, itemPath)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_DELETE, itemPath); + } + return false; + } } } return true; Index: src/ioslaves/file/file_unix.cpp =================================================================== --- src/ioslaves/file/file_unix.cpp +++ src/ioslaves/file/file_unix.cpp @@ -548,16 +548,20 @@ } if (::rename(_src.data(), _dest.data())) { - if ((errno == EACCES) || (errno == EPERM)) { - error(KIO::ERR_ACCESS_DENIED, dest); - } else if (errno == EXDEV) { - error(KIO::ERR_UNSUPPORTED_ACTION, QStringLiteral("rename")); - } else if (errno == EROFS) { // The file is on a read-only filesystem - error(KIO::ERR_CANNOT_DELETE, src); - } else { - error(KIO::ERR_CANNOT_RENAME, src); + if (auto err = execWithElevatedPrivilege(RENAME, _src, _dest)) { + if (!err.wasCanceled()) { + if ((errno == EACCES) || (errno == EPERM)) { + error(KIO::ERR_ACCESS_DENIED, dest); + } else if (errno == EXDEV) { + error(KIO::ERR_UNSUPPORTED_ACTION, QStringLiteral("rename")); + } else if (errno == EROFS) { // The file is on a read-only filesystem + error(KIO::ERR_CANNOT_DELETE, src); + } else { + error(KIO::ERR_CANNOT_RENAME, src); + } + } + return; } - return; } finished(); @@ -573,8 +577,12 @@ if ((flags & KIO::Overwrite)) { // Try to delete the destination if (unlink(QFile::encodeName(dest).constData()) != 0) { - error(KIO::ERR_CANNOT_DELETE, dest); - return; + if (auto err = execWithElevatedPrivilege(DEL, dest)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_DELETE, dest); + } + return; + } } // Try again - this won't loop forever since unlink succeeded symlink(target, destUrl, flags); @@ -589,9 +597,12 @@ return; } } else { - // Some error occurred while we tried to symlink - error(KIO::ERR_CANNOT_SYMLINK, dest); - return; + if (auto err = execWithElevatedPrivilege(SYMLINK, dest, target)) { + if (!err.wasCanceled()) { + // Some error occurred while we tried to symlink + error(KIO::ERR_CANNOT_SYMLINK, dest); } + return; + } } } finished(); @@ -609,14 +620,18 @@ // qDebug() << "Deleting file "<< url; if (unlink(_path.data()) == -1) { - if ((errno == EACCES) || (errno == EPERM)) { - error(KIO::ERR_ACCESS_DENIED, path); - } else if (errno == EISDIR) { - error(KIO::ERR_IS_DIRECTORY, path); - } else { - error(KIO::ERR_CANNOT_DELETE, path); + if (auto err = execWithElevatedPrivilege(DEL, _path)) { + if (!err.wasCanceled()) { + if ((errno == EACCES) || (errno == EPERM)) { + error(KIO::ERR_ACCESS_DENIED, path); + } else if (errno == EISDIR) { + error(KIO::ERR_IS_DIRECTORY, path); + } else { + error(KIO::ERR_CANNOT_DELETE, path); + } + } + return; } - return; } } else { @@ -631,11 +646,15 @@ } } if (QT_RMDIR(_path.data()) == -1) { - if ((errno == EACCES) || (errno == EPERM)) { - error(KIO::ERR_ACCESS_DENIED, path); - } else { - // qDebug() << "could not rmdir " << perror; - error(KIO::ERR_CANNOT_RMDIR, path); + if (auto err = execWithElevatedPrivilege(RMDIR, _path)) { + if (!err.wasCanceled()) { + if ((errno == EACCES) || (errno == EPERM)) { + error(KIO::ERR_ACCESS_DENIED, path); + } else { + // qDebug() << "could not rmdir " << perror; + error(KIO::ERR_CANNOT_RMDIR, path); + } + } return; } } @@ -678,16 +697,20 @@ } if (::chown(_path.constData(), uid, gid) == -1) { - switch (errno) { - case EPERM: - case EACCES: - error(KIO::ERR_ACCESS_DENIED, path); - break; - case ENOSPC: - error(KIO::ERR_DISK_FULL, path); - break; - default: - error(KIO::ERR_CANNOT_CHOWN, path); + if (auto err = execWithElevatedPrivilege(CHOWN, _path, uid, gid)) { + if (!err.wasCanceled()) { + switch (errno) { + case EPERM: + case EACCES: + error(KIO::ERR_ACCESS_DENIED, path); + break; + case ENOSPC: + error(KIO::ERR_DISK_FULL, path); + break; + default: + error(KIO::ERR_CANNOT_CHOWN, path); + } + } } } else { finished();