POSIX имеет три основных набора разрешений:
- пользователь : владелец файла,
- group : группа файла (часто только основная группа, к которой принадлежит владелец файла, но не всегда), и
- прочее (a.k.a. "world"): любой, кто не принадлежит группе файла, но также не является владельцем файла
Предполагая, что вам нужно поведение, подобное 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
Я упоминаю об этом только потому, что легче поддерживать что-то, где логика не разделена между директивами перед компиляцией, не говоря уже об отсутствии дублирования.