POSIX имеет три основных набора разрешений:
- пользователь: владелец файла,
- группа: группа файла (часто основная группа, к которой принадлежит владелец файла, но не всегда), и
- другой (также известный как "мир"): любой человек, не входящий в группу файла, но не являющийся владельцем файла.
Предполагая, что вам нужно поведение, подобное Windows, вы захотите установить для них все только для чтения (т.е. удалить все разрешения на запись); это то же самое, что WINE делает в Linux. Это не так просто в QB64 из-за того, сколько POSIX оставляет за реализацией (например, где st_mode
появляется в struct stat
), поэтому вам нужно написать заголовок DECLARE LIBRARY
, который позволит вам обернуть функциональность на основе C, если вы этого хотите. для работы как в Linux, так и в OS X (и в любой другой системе, на которой может работать QB64):
#define _XOPEN_SOURCE 700
#include <sys/stat.h> // chmod, stat
// Make a file read-only for all users.
// Returns 0 on success, -1 on error.
int makeReadOnlyPOSIX(const char *path)
{
int n;
struct stat fileInfo;
const mode_t noWriteMask = (
S_IRUSR | S_IRGRP | S_IROTH
| S_IXUSR | S_IXGRP | S_IXOTH
| S_ISUID | S_ISGID
#ifdef S_ISVTX
| S_ISVTX
#endif
);
n = stat(path, &fileInfo);
if (n == -1) return n;
n = chmod(path, fileInfo.st_mode & noWriteMask);
return n;
}
Однако ваш исходный код QB64 также имеет недостаток: вы проверяете существование файла, а затем изменяете атрибуты файла, что является определением Уязвимость TOCTOU (см. Пример 2, примерный эквивалент вашего кода в POSIX C).
Чтобы решить проблему, просто получите и установите права доступа к файлу. Если в какой-то момент возникла проблема, вы можете либо убедиться, что файл существует, и распечатать сообщение об ошибке (или распечатать, что его не существует), либо просто распечатать сообщение об ошибке, независимо от того, существует файл или нет. Чтобы сделать код чище в Windows (поскольку GetFileAttributes&
может возвращать значение ошибки), вы можете создать функцию C, которая делает то же самое, что и makeReadOnlyPOSIX
:
#include <windows.h>
int makeReadOnlyWindows(const char *path)
{
DWORD attrs;
attrs = GetFileAttributesA(path);
if (attrs == INVALID_FILE_ATTRIBUTES)
return -1;
return (int)SetFileAttributesA(path, attrs & 0x01) - 1;
}
Затем вы можете написать это в своем коде QB64:
$IF WIN = 0 THEN
IF makeReadOnlyPOSIX(ASCIIZ) = 0 THEN
$ELSE
IF makeReadOnlyWindows(ASCIIZ) = 0 THEN
$END IF
PRINT "Success."
ELSE
PRINT "Error."
END IF
Конечно, я предполагаю, что $IF ... THEN
, $ELSE
и т. д. в QB64 работают как препроцессор C (т. е. генерируют правильный вывод на основе оценок условий), но даже если это так, вы можете предпочесть что-то более похожее на это:
$IF WIN = 0 THEN
IF makeReadOnlyPOSIX(ASCIIZ) = 0 THEN
PRINT "Success."
ELSE
PRINT "Error."
END IF
$ELSE
IF makeReadOnlyWindows(ASCIIZ) = 0 THEN
PRINT "Success."
ELSE
PRINT "Error."
END IF
$END IF
Изменить
Если вы хотите, чтобы ваш код работал с тем же именем функции, вы можете сделать в QB64 следующее:
$IF WIN = 0 THEN
DECLARE LIBRARY "posixHeader"
FUNCTION makeReadOnly ALIAS makeReadOnlyPOSIX& (fname$)
END DECLARE
$ELSE
DECLARE LIBRARY "winHeader"
FUNCTION makeReadOnly ALIAS makeReadOnlyWindows& (fname$)
END DECLARE
$END IF
Таким образом, вы можете просто использовать что-то вроде следующего в своем реальном коде:
IF makeReadOnly(ASCIIZ) = 0 THEN
PRINT "Success."
ELSE
PRINT "Error."
END IF
Я упоминаю об этом только потому, что легче поддерживать что-то, где логика не разделена между директивами прекомпиляции, не говоря уже об отсутствии дублирования.
person
Community
schedule
23.06.2018