Введение
Права доступа к файлам — одна из тех областей, где различия между Windows, Linux и macOS особенно заметны. POSIX-системы используют модель «владелец/группа/прочие» с битами чтения, записи и выполнения, в то время как Windows опирается на ACL (списки контроля доступа) NTFS. Qt пытается абстрагировать эти различия через QFile::permissions() и QFileDevice::Permissions, но полного паритета между платформами не существует.
Концепция
QFileDevice::Permissions — это набор флагов (ReadOwner, WriteOwner, ExeOwner, ReadGroup, WriteGroup, ExeGroup, ReadOther, WriteOther, ExeOther, плюс специальные ReadUser/WriteUser/ExeUser), которые в сумме напоминают классические Unix-права rwxrwxrwx. Метод QFile::permissions(path) (статический) или QFile::permissions() (метод объекта) позволяет прочитать текущие права, а setPermissions() — установить новые.
На Windows эта модель — упрощённое отображение реальных ACL NTFS. Qt транслирует POSIX-подобные флаги в базовые атрибуты («только чтение» и т.п.), но не предоставляет полного управления ACL — для этого нужны платформенные API через QFile::handle() или сторонние библиотеки.
Пример кода: Работа с правами доступа к файлам в Qt
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QCoreApplication>
void printPermissions(const QString &path)
{
QFileInfo info(path);
if (!info.exists()) {
qWarning() << "Файл не существует:" << path;
return;
}
QFileDevice::Permissions perms = QFile::permissions(path);
QString result;
result += (perms & QFileDevice::ReadOwner) ? "r" : "-";
result += (perms & QFileDevice::WriteOwner) ? "w" : "-";
result += (perms & QFileDevice::ExeOwner) ? "x" : "-";
result += (perms & QFileDevice::ReadGroup) ? "r" : "-";
result += (perms & QFileDevice::WriteGroup) ? "w" : "-";
result += (perms & QFileDevice::ExeGroup) ? "x" : "-";
result += (perms & QFileDevice::ReadOther) ? "r" : "-";
result += (perms & QFileDevice::WriteOther) ? "w" : "-";
result += (perms & QFileDevice::ExeOther) ? "x" : "-";
qDebug() << path << ":" << result
<< "(владелец:" << info.owner() << ")"
<< "только чтение:" << !info.isWritable();
}
bool makeReadOnly(const QString &path)
{
QFileDevice::Permissions perms = QFile::permissions(path);
// Снимаем все права на запись, оставляя права на чтение
perms &= ~(QFileDevice::WriteOwner | QFileDevice::WriteGroup | QFileDevice::WriteOther);
if (!QFile::setPermissions(path, perms)) {
qWarning() << "Не удалось изменить права доступа для" << path;
return false;
}
return true;
}
bool makeExecutable(const QString &path)
{
QFileDevice::Permissions perms = QFile::permissions(path);
perms |= QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeUser;
return QFile::setPermissions(path, perms);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QString testFile = "script.sh";
QFile f(testFile);
f.open(QIODevice::WriteOnly);
f.write("#!/bin/bash\necho Hello from Qt\n");
f.close();
printPermissions(testFile);
if (makeExecutable(testFile)) {
qDebug() << "Файл сделан исполняемым";
printPermissions(testFile);
}
if (makeReadOnly(testFile)) {
qDebug() << "Файл сделан доступным только для чтения";
printPermissions(testFile);
}
return 0;
}
Пояснения к коду
Флаги Permissions объединяются битовыми операциями |, &, ~, что позволяет точечно изменять отдельные биты, не затрагивая остальные — именно так и нужно работать с правами, а не присваивать новое значение «с нуля», теряя существующие настройки.
QFileInfo::owner(), ownerId(), group(), groupId() дают информацию о владельце на POSIX-системах; на Windows эти методы возвращают данные, полученные через соответствующие Win32 API, но концептуально модель «владелец/группа» там вторична по отношению к ACL.
Подводные камни
- Windows не различает Owner/Group/Other в классическом смысле. Установка
WriteGroupилиWriteOtherбезWriteOwnerна Windows может не дать ожидаемого эффекта — реальное поведение определяется ACL файла, а не этими тремя уровнями. Если нужен точный контроль доступа на Windows, требуется работать сSetNamedSecurityInfoчерез WinAPI напрямую.
ExeOwnerна Windows. Понятие «исполняемый файл» на Windows определяется расширением (.exe,.bat) и ассоциациями, а не битом прав доступа, как в Unix. УстановкаExeOwnerдля.txt-файла на Windows не сделает его исполняемым в общепринятом смысле.
- Права не применяются мгновенно к открытым файловым дескрипторам. Изменение прав через
setPermissions()влияет на новые попытки открытия файла; уже открытыйQFileпродолжает работать с правами, действовавшими на момент открытия (зависит от ОС).
- Сетевые файловые системы и контейнеры. Внутри Docker-контейнеров или на смонтированных сетевых ресурсах (особенно при использовании bind-mount с Windows-хостом) права могут отображаться некорректно или игнорироваться полностью.
- Требуются права самого процесса.
setPermissions()завершится ошибкой, если процесс не имеет прав на изменение атрибутов файла (например, не является владельцем на Linux и не запущен от root/sudo).
- umask и права по умолчанию. Qt не учитывает
umaskпри создании новых файлов черезQFile— по умолчанию создаются файлы с правами, зависящими от ОС и системных настроек, и их может потребоваться скорректировать сразу после создания черезsetPermissions().
При разработке кросс-платформенных приложений важно помнить: QFile::permissions() даёт достаточный уровень абстракции для большинства задач (сделать файл доступным только для чтения, проверить, можно ли в него писать), но не заменяет платформо-специфичный API там, где нужен тонкий контроль через ACL.
================================================================================